【问题标题】:android javamail api imap over sslandroid javamail api imap over ssl
【发布时间】:2011-10-17 09:08:44
【问题描述】:

我想在 android 上获取我的 Exchange 电子邮件,为此我正在使用适用于 android 的 javamail api...它在使用 imap 的 gmail 和 yahoo 上效果很好。 问题是我的交换服务器有自签名证书所以android不太喜欢这个我得到03-14 12:46:13.698: WARN/System.err(281): javax.mail.MessagingException: Not trusted server certificate;

我看过这个例子:Sending Email in Android using JavaMail API without using the default/built-in app 有人通过 ssl 发送示例。我想我可以使用该 JSSEProvider 来接受我的自签名证书,但我不知道如何使用它。

请帮帮我!

【问题讨论】:

    标签: android imap ssl-certificate jakarta-mail


    【解决方案1】:

    我遇到了同样的问题,并设法通过配置信任管理器来解决它,详情请参阅 http://java.sun.com/products/javamail/javamail-1.4.2/SSLNOTES142.txt

    我所做的是创建自己的 TrustManager:

    package com.myapp;
    import javax.net.ssl.X509TrustManager;
    import java.security.cert.X509Certificate;
    
    /**
     * DummyTrustManager - NOT SECURE
     */
    public class DummyTrustManager implements X509TrustManager {
    
        public void checkClientTrusted(X509Certificate[] cert, String authType) {
        // everything is trusted
        }
    
        public void checkServerTrusted(X509Certificate[] cert, String authType) {
        // everything is trusted
        }
    
        public X509Certificate[] getAcceptedIssuers() {
        return new X509Certificate[0];
        }
    }
    

    并在我自己的 SSLSocketFactory 中使用它:

    package com.myapp;
    
    import java.io.IOException;
    import java.net.InetAddress;
    import java.net.Socket;
    
    import javax.net.SocketFactory;
    import javax.net.ssl.*;
    
    
    /**
     * DummySSLSocketFactory
     */
    public class DummySSLSocketFactory extends SSLSocketFactory {
        private SSLSocketFactory factory;
    
        public DummySSLSocketFactory() {
        try {
            SSLContext sslcontext = SSLContext.getInstance("TLS");
            sslcontext.init(null,
                     new TrustManager[] { new DummyTrustManager()},
                     null);
            factory = (SSLSocketFactory)sslcontext.getSocketFactory();
        } catch(Exception ex) {
            // ignore
        }
        }
    
        public static SocketFactory getDefault() {
        return new DummySSLSocketFactory();
        }
    
        public Socket createSocket() throws IOException {
        return factory.createSocket();
        }
    
            public Socket createSocket(Socket socket, String s, int i, boolean flag)
                    throws IOException {
        return factory.createSocket(socket, s, i, flag);
        }
    
        public Socket createSocket(InetAddress inaddr, int i,
                    InetAddress inaddr1, int j) throws IOException {
        return factory.createSocket(inaddr, i, inaddr1, j);
        }
    
        public Socket createSocket(InetAddress inaddr, int i)
                    throws IOException {
        return factory.createSocket(inaddr, i);
        }
    
        public Socket createSocket(String s, int i, InetAddress inaddr, int j)
                    throws IOException {
        return factory.createSocket(s, i, inaddr, j);
        }
    
        public Socket createSocket(String s, int i) throws IOException {
        return factory.createSocket(s, i);
        }
    
        public String[] getDefaultCipherSuites() {
        return factory.getDefaultCipherSuites();
        }
    
        public String[] getSupportedCipherSuites() {
        return factory.getSupportedCipherSuites();
        }
    }
    

    要让它在 javamail-android 中工作,您需要在获得 Session 实例之前指定新的 SSLSocketFactory:

        Properties props = new Properties();
        props.setProperty( "mail.imaps.socketFactory.class", "com.myapp.DummySSLSocketFactory" );
        session = Session.getDefaultInstance( props );
    

    现在使用我们定义的 TrustManager 代替默认的,所有证书都将被接受。

    显然,盲目接受所有证书存在一些安全问题,我建议您检查一下您的 TrustManager,否则您可能会面临各种安全问题(例如中间人攻击) .另外,我只会在你真正需要的地方使用它:例如你说 GMail 和 Ymail 正在工作,所以在连接到它们时我不会使用这种机制。

    我会放入一个异常处理程序来捕获“证书不受信任”异常,并在实际覆盖 TrustManager 之前提示用户接受不受信任的证书(并发出必要的警告,只对绝对受信任的服务器执行此操作) .

    【讨论】:

    • 永远不要这样做。它信任每个证书,您也可以完全禁用 SSL。攻击者在这里的工作非常轻松。绝对可以将一组已定义的受信任证书添加到信任存储中,并且可以询问用户是否要接受该证书。正如你警告的那样,我收回了我的反对票。
    【解决方案2】:

    我遇到了同样的问题,并以我认为更简洁更简洁的方式解决了它。我使用了 Mark Allison 链接的相同参考,但我没有覆盖 SSLSocketFactory 并实现您自己的 TrustManager,而是添加了以下内容:

    MailSSLSocketFactory sf = new MailSSLSocketFactory();
    sf.setTrustAllHosts(true);
    // or
    // sf.setTrustedHosts(new String[] { "my-server" });
    props.put("mail.smtp.ssl.enable", "true");
    // also use following for additional safety
    //props.put("mail.smtp.ssl.checkserveridentity", "true");
    props.put("mail.smtp.ssl.socketFactory", sf);
    

    有关更多信息,请查看链接的“套接字工厂”部分:http://java.sun.com/products/javamail/javamail-1.4.2/SSLNOTES142.txt

    值得注意的是,当我这样做时,我必须使用“imap”商店,而不是“imaps”:

    Store store = session.getStore("imap");
    

    这是我的完整代码,在访问 Exchange 2010 服务器时非常适合我:

    import javax.mail.*;
    import java.util.*;
    import com.sun.mail.util.MailSSLSocketFactory;
    .
    .
    .
    
    // Set the socket factory to trust all hosts
    MailSSLSocketFactory sf = new MailSSLSocketFactory();
    sf.setTrustAllHosts(true);
    
    // create the properties for the Session
    Properties props = new Properties();
    props.put("mail.imap.ssl.enable", "true");
    props.put("mail.imap.ssl.socketFactory", sf);
    
    // Get session
    Session session = Session.getInstance(props, null);
    //session.setDebug(true);
    
    // Get the store
    Store store = session.getStore("imap");
    System.out.println("Establishing connection with IMAP server.");
    
    store.connect("host", 993, "username", "password");
    System.out.println("Connection established with IMAP server.");
    
    // List all folders (including subfolders)
    Folder[] allFolders = store.getDefaultFolder().list("*");
    
    store.close();
    

    【讨论】:

      猜你喜欢
      • 2014-02-12
      • 2011-06-11
      • 2017-06-11
      • 2014-04-22
      • 2013-05-29
      • 1970-01-01
      • 2016-10-19
      • 2016-03-22
      • 2012-01-09
      相关资源
      最近更新 更多