Java源碼安全審查


最近業務需要出一份Java Web應用源碼安全審查報告, 對比了市面上數種工具及其分析結果, 基於結果總結了一份規則庫. 本文目錄結構如下: 

檢測工具

FindSecurityBugs

基於class文件分析, 他是大名鼎鼎的findbugs的插件,  安裝比較簡單. 在findbugs官網下載安裝包,  插件jar, 把jar放到findbugs-3.0.1\plugin目錄.

打開bin路徑下的findbugs.bat啟動軟件. 在菜單欄 - 編輯 - 選項可以查看插件是否啟用成功.

新建項目, 輸入名稱, 選擇需要分析的class路徑, 引用的第三方包地址, 源碼路徑, 點擊Analyze即可. 

最終生成的結果可以轉為html報告, 也可以導出xml文件, 在findbugs分析查看. 本文主要關注Security一欄.

代碼衛士

360出品, 名聲似乎不太好, 誤報比較多, 不過結果也有一定的參考價值. 如果代碼在碼雲的話, 點服務一欄, 可以在線掃描碼雲庫里的源碼, 本地代碼要去官網申請試用.

掃描結果

Fortify

HP出品的老牌掃描工具, 網上有破解的. 安裝過程一路next即可. 最后啟動AuditWorkBench, 選擇scan java project, 耐心等待.

結果跟findbugs類似.

CodePecker

啄木鳥源碼分析, 國內的一款也是基於字節碼分析的工具, 提供了一個收費的在線審計平台. 知乎有不少軟文, 沒找到免費試用的地方, 放棄了.

結果分析

代碼注入


命令注入

命令注入是指應用程序執行命令的字符串或字符串的一部分來源於不可信賴的數據源,程序沒有對這些不可信賴的數據進行驗證、過濾,導致程序執行惡意命令的一種攻擊方式。

        String dir = request.getParameter("dir");
        Process proc = Runtime.getRuntime().exec("cmd.exe /c dir" + dir);

如果攻擊者傳遞了一個dir形式為"dummy && del c:\\dbms\\*.*"的字符串,那么該段代碼將會在執行其他指定命令的同時執行這條刪除命令。 

修復方式

    (1)程序對非受信的用戶輸入數據進行凈化,刪除不安全的字符。
    (2)限定輸入類型, 創建一份安全字符串列表,限制用戶只能輸入該列表中的數據。

復制代碼
 1         // 方式1
 2         if (!Pattern.matches("[0-9A-Za-z@.]+", dir)) {
 3             // Handle error
 4         }
 5 
 6         // 方式2
 7         int number = Integer.parseInt(request.getParameter("dir"));
 8         switch (number) {
 9             case 1:
10                 btype = "tables"
11                 break; // Option 1
12             case 2:
13                 btype = "users"
14                 break; // Option 2
15             ......
復制代碼

HTTP響應截斷

程序從一個不可信賴的數據源獲取數據,未進行驗證就置於HTTP頭文件中發給用戶,可能會導致HTTP響應截斷攻擊。

    String author = request.getParameter(AUTHOR_PARAM);
    ... 
    Cookie cookie = new Cookie("author", author);
    cookie.setMaxAge(cookieExpiration);
    response.addCookie(cookie);

那么如果攻擊者提交的是一個惡意字符串,比如“Wiley Hacker\r\nHTTP/1.1 200 OK\r\n...”,那么HTTP響應就會被分割成以下形式的兩個響應:

    HTTP/1.1 200 OK    

 ...    

    Set-Cookie: author=Wiley Hacker    

    HTTP/1.1 200 OK    

    ...

這樣第二個響應已完全由攻擊者控制,攻擊者可以用所需的頭文件和正文內容構建該響應實施攻擊。

修復方式

防止HTTP響應截斷攻擊的最安全的方法是創建一份安全字符白名單,只接受完全由這些受認可的字符組成的輸入出現在HTTP響應頭文件中。

復制代碼
        String author = request.getParameter(AUTHOR_PARAM);
        if (Pattern.matches("[0-9A-Za-z]+", author)) {
            ...
            Cookie cookie = new Cookie("author", author);
            cookie.setMaxAge(cookieExpiration);
            response.addCookie(cookie);
        }
復制代碼

SQL注入

SQL注入是一種數據庫攻擊手段。攻擊者通過向應用程序提交惡意代碼來改變原SQL語句的含義,進而執行任意SQL命令,達到入侵數據庫乃至操作系統的目的。

       String sqlString = "SELECT * FROM db_user WHERE username = '" + username + "' AND password = '" + pwd + "'"; 
            Statement stmt = connection.createStatement(); 
            ResultSet rs = stmt.executeQuery(sqlString); 

攻擊者能夠替代username和password中的任意字符串,它們可以使用下面的關於password的字符串進行SQL注入。

SELECT * FROM db_user WHERE username='' AND password='' OR '1'='1' 

修復方式

造成SQL注入攻擊的根本原因在於攻擊者可以改變SQL查詢的上下文,使程序員原本要作為數據解析的數值,被篡改為命令了。防止SQL注入的方法如下:
    (1)正確使用參數化API進行SQL查詢。
    (2)如果構造SQL指令時需要動態加入約束條件,可以通過創建一份合法字符串列表,使其對應於可能要加入到SQL指令中的不同元素,來避免SQL注入攻擊。

        String sqlString = "select * from db_user where username=? and password=?";
        PreparedStatement stmt = connection.prepareStatement(sqlString);
        stmt.setString(1, username);
        stmt.setString(2, pwd);
        ResultSet rs = stmt.executeQuery();

正則表達式注入

數據被傳遞至應用程序並作為正則表達式使用。可能導致線程過度使用 CPU 資源,從而導致拒絕服務攻擊。 

下述代碼java中字符串的split, replaceAll均支持正則的方式, 導致CPU掛起.

1         final String input = "0000000000000000000000000000000000000000000000";
2         long startTime = System.currentTimeMillis();
3         System.out.println(input.split("(0*)*A"));
4         System.out.println("耗時:" + (System.currentTimeMillis() - startTime) + "ms");
  • 該正則的意思是說匹配器在輸入的末尾並沒有檢測到”A”。現在外側的限定符后退一次,內存的則前進一次,如此重復,無法得到結果。

  • 因此,匹配器逐步回退,並嘗試所有的組合以找出匹配符號。它最終將返回(沒有匹配的結果),但是該過程的復雜性是指數型的(輸入中添加一個字符加倍了運行時間)

修復方式

使用線程池 + Future, 限定執行時間, 並捕獲異常.

復制代碼
 1         ExecutorService service = Executors.newFixedThreadPool(1);
 2         Future result = service.submit(new Callable<Object>() {
 3             @Override
 4             public Object call() {
 5                 final String input = "0000000000000000000000000000000000000000000000";
 6                 return input.split("(0*)*A");
 7             }
 8         });
 9         service.shutdown();
10         System.out.println(result.get(5, TimeUnit.SECONDS));
復制代碼

LDAP注入

LDAP注入是指客戶端發送查詢請求時,輸入的字符串中含有一些特殊字符,導致修改了LDAP本來的查詢結構,從而使得可以訪問更多的未授權數據的一種攻擊方式。

以下代碼動態構造一個 LDAP 查詢,並對其加以執行,該查詢可以檢索所有報告給指定經理的雇員記錄。該經理的名字是從 HTTP 請求中讀取的,因此不可信任。

1     DirContext ctx = new InitialDirContext(env);
2     String managerName = request.getParameter("managerName");
3     //retrieve all of the employees who report to a manager
4     String filter = "(manager=" + managerName + ")";
5     NamingEnumeration employees = ctx.search("ou=People,dc=example,dc=com",filter);

如果攻擊者為 managerName 輸入字符串 Hacker, Wiley)(|(objectclass=*),則該查詢會變成:
  (manager=Hacker, Wiley)(|(objectclass=*))

根據執行查詢的權限,增加 |(objectclass=*) 條件會導致篩選器與目錄中的所有輸入都匹配,而且會使攻擊者檢索到有關用戶輸入池的信息。

如果攻擊者能夠控制查詢的命令結構,那么這樣的攻擊至少會影響執行 LDAP 查詢的用戶可以訪問的所有記錄。

修復方式

用白名單的方法,確保LDAP查詢中由用戶控制的數值完全來自於預定的字符集合,應不包含任何LDAP元字符。

比如使用Spring框架中EqualsFilter類來構造一個編碼得當的篩選器字符串.

    DirContext ctx = new InitialDirContext(env);
    String managerName = request.getParameter("managerName");
    //retrieve all of the employees who report to a manager
    EqualsFilter filter = new EqualsFilter("manager", managerName);
    NamingEnumeration employees = ctx.search("ou=People,dc=example,dc=com",filter.toString());

輸入驗證


拒絕服務

拒絕服務是攻擊者通過極度消耗應用資源,以致程序崩潰或其他合法用戶無法進行使用的一種攻擊方式。

例如解壓文件前,未檢查文件大小,攻擊者可以通過提供一個超大文件,實施DOS攻擊。

1    FileOutputStream fos = new FileOutputStream(entry.getName());
2     dest = new BufferedOutputStream(fos, BUFFER);
3     while ((count = zis.read(data, 0, BUFFER)) != -1) {
4         dest.write(data, 0, count);
5     }

修復方式

對涉及到系統資源的外部數據應該進行嚴格校驗,防止無限制的輸入。對於用戶上傳的文件, 要在后台進行大小校驗. 

比如對解壓文件進行驗證,超過100M,將拋出異常。

1     if (entry.getSize() > TOOBIG) {
2         throw new IllegalStateException("File to be unzipped is huge.");
3     }

重定向參數

應用程序允許未驗證的用戶輸入控制重定向中的URL,可能會導致攻擊者發動釣魚攻擊。

         String url = request.getParameter("url");
          response.sendRedirect(url);

修復方式

創建一份合法URL列表,用戶只能從中進行選擇,進行重定向操作。

XML實體注入

簡稱XXE攻擊, XML解析器中默認會解析xml中的ENTITY來支持全局變量以及外部文件讀取.

如果從web請求中獲取xml內容, 並在服務器端解析, 則可能導致xxe攻擊.

1         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
2         DocumentBuilder db = dbf.newDocumentBuilder();
3         Document doc = db.parse(xmlFile);
4         NodeList list = doc.getElementsByTagName("active");

修復方式

    (1)關閉XML實體解析

    (2)使用JSON來替代XML做數據傳輸

1 DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();
2 dbf.setExpandEntityReferences(false);

資源注入

使用用戶輸入控制資源標識符,借此攻擊者可以訪問或修改其他受保護的系統資源。當滿足以下兩個條件時,就會發生資源注入:
    (1)攻擊者可以指定已使用的標識符來訪問系統資源。例如,攻擊者可能可以指定用來連接到網絡資源的端口號。 
    (2)攻擊者可以通過指定特定資源來獲取某種權限,而這種權限在一般情況下是不可能獲得的。例如,程序可能會允許攻擊者把敏感信息傳輸到第三方服務器。

1         URL url = new URL(request.getParameter("remoteURL"));
2         URLConnection connection = url.openConnection();
3          ...
4         String remotePort = request.getParameter("remotePort");
5         ServerSocket srvr = new ServerSocket(remotePort);
6         Socket skt = srvr.accept();

修復方式

使用白名單策略, 限制資源文件讀取和訪問.

日志偽造

允許日志記錄未經驗證的用戶輸入,會導致日志偽造攻擊。攻擊者可能通過破壞文件格式或注入意外的字符,從而使文件無法使用。

更陰險的攻擊可能會導致日志文件中的統計信息發生偏差, 掩護攻擊者的跟蹤軌跡.

1     if (loginSuccessful) {
2        logger.severe("User login succeeded for: " + username);
3     } else {
4         logger.severe("User login failed for: " + username);
5     }

攻擊者可以將username替換為一個多行字符串,如下所示:
    jack
    2013-7-30 java.util.logging.LogManager log
    Server: User login succeeded for: Tom

修復方式

對不可信賴的數據進行校驗。

另外日志中不應該出現敏感數據, 例如密碼, 手機號, 郵箱這些信息.

1 if (!Pattern.matches("[A-Za-z0-9_]+", username)) {
2        // Unsanitized username
3        logger.severe("User login failed for unauthorized user");
4     } else if (loginSuccessful) {
5         logger.severe("User login succeeded for: " + username);
6     } 

文件校驗

對於用戶上傳的文件, 需要在前后台雙重校驗, 校驗后綴, 文件大小, 二進制頭等等.

其他可輸入項, 也要做前后台雙重校驗, 防止中間人修改數據.

修復方式 

對文件二進制頭進行校驗

復制代碼
 1     static {
 2         MAGIC_NUMBER.put("jpg", new String[]{"FFD8"});
 3         MAGIC_NUMBER.put("gif", new String[]{"47494638"});
 4         MAGIC_NUMBER.put("png", new String[]{"89504E470D0A1A0A"});
 5         MAGIC_NUMBER.put("pdf", new String[]{"25504446"});
 6         MAGIC_NUMBER.put("doc", new String[]{"D0CF11E0A1B11AE1", "7B5C72746631"}); 
 7         MAGIC_NUMBER.put("xls", new String[]{"D0CF11E0A1B11AE1"});
 8         MAGIC_NUMBER.put("ppt", new String[]{"D0CF11E0A1B11AE1"});
 9         MAGIC_NUMBER.put("docx", new String[]{"504B0304"});
10         MAGIC_NUMBER.put("xlsx", new String[]{"504B0304"});
11         MAGIC_NUMBER.put("pptx", new String[]{"504B0304"});
12     }
13 
14     /**
15      * 在檢驗范圍內(MAGIC_NUMBER.keySet(): jpg, gif, png, pdf, xls, ppt, doc, xlsx, pptx, docx)
16      * 且文件后綴和文件二進制頭不一致。返回false
17      */
18     public static boolean checkFileType(byte[] content, String suffix) {
19         if (!MAGIC_NUMBER.keySet().contains(suffix)) {
20             return true;
21         }
22 
23         byte[] bytes = Arrays.copyOfRange(content, 0, Math.min(content.length, MAGIC_HEADER_LENGTH));
24         String fileCode = getFileHeader(bytes);
25         for (String magicNumber : MAGIC_NUMBER.get(suffix)) {
26             if (fileCode.toUpperCase().startsWith(magicNumber)) {
27                 return true;
28             }
29         }
30         return false;
31     }
復制代碼

 密碼管理


硬編碼密碼

程序中采用硬編碼方式處理密碼,一方面會降低系統安全性,另一方面不易於程序維護。

1         private String rootManagerPassword = DEFAULTADMINPASSWORD;
2         ......
3         if (password == null) {
4             password = "123456";
5         }

修復方式

程序中所需密碼應從配置文件中獲取經過加密的密碼值。

弱加密

在安全性要求較高的系統中,使用不安全的加密算法(如DES、RC4、RC5等),將無法保證敏感數據的保密性。

1             Cipher des = Cipher.getInstance("DES");
2             SecretKey key = KeyGenerator.getInstance("DES").generateKey();

修復方式

使用安全的加密算法(如AES、3DES、RSA)對敏感數據進行加密。

1             Cipher aes = Cipher.getInstance("AES");
2             KeyGenerator kg = KeyGenerator.getInstance("AES");
3             kg.init(128);
4             SecretKey key = kg.generateKey();

不安全的Hash

在安全性要求較高的系統中,不應使用被業界公認的不安全的哈希算法(如MD2、MD4、MD5、SHA、SHA1等)來保證數據的完整性。

1             MessageDigest messageDigest = MessageDigest.getInstance("MD5");
2             messageDigest.update(stringID.getBytes());

修復方式

采用散列值>=224比特的SHA系列算法(如SHA-224、SHA-256、SHA-384和SHA-512)來保證敏感數據的完整性。

1         md = MessageDigest.getInstance("SHA-256");
2         md.update(bt);
3         strDes = bytes2Hex(md.digest()); // to HexString

不安全的隨機數

Java API中提供了java.util.Random類實現PRNG(),該PRNG是可移植和可重復的,如果兩個java.util.Random類的實例使用相同的種子,會在所有Java實現中生成相同的數值序列。

復制代碼
 1         // Random對象r和s設置了相同的種子,因此 i == j 以及數組b[]和c[]的相應值是相等的。
 2         Random r = new Random(12345);
 3         int i = r.nextInt();
 4         byte[] b = new byte[4];
 5         r.nextBytes(b);
 6 
 7         Random s = new Random(12345);
 8         int j = s.nextInt();
 9         byte[] c = new byte[4];
10         s.nextBytes(c);
復制代碼

修復方式

使用更安全的隨機數生成器,如java.security.SecureRandom類。

1         SecureRandom number = SecureRandom.getInstance("SHA1PRNG");
2         System.out.println(number.nextInt()  + "  " + number.nextInt());

跨站腳本


XSS

應用程序從數據庫或其它后端數據存儲獲取不可信賴的數據,在未檢驗數據是否存在惡意代碼的情況下,便將其傳送給了Web用戶,應用程序將易於受到存儲型XSS攻擊。

1         PrintWriter writer = WebUtils.createPrintWriter(res);
2         writer.print(str);
3         writer.flush();
4         writer.close();

修復方式

對輸出的字符串內容進行html轉義編碼.

復制代碼
public static String replaceScript4Xss(String message) {
    if (StringUtils.isEmpty(message)) {
        return StringUtils.EMPTY;
    }
    StringBuffer builder = new StringBuffer(message.length() * 2);
    CharacterIterator it = new StringCharacterIterator(message);
    for (char ch = it.first(); ch != CharacterIterator.DONE; ch = it.next()) {
        if ((((ch > '`') && (ch < '{')) || ((ch > '@') && (ch < '[')))
                || (((ch == ' ') || ((ch > '/') && (ch < ':'))) || (((ch == '.') || (ch == ',')) || ((ch == '-') || (ch == '_'))))) {
            builder.append(ch);
        } else {
            builder.append("&#" + (int) ch + ";");
        }
    }
    return builder.toString();
}
復制代碼

CSRF跨站

跨站請求偽造(CSRF)是偽造客戶端請求的一種攻擊。應用程序允許用戶提交不包含任何保密信息的請求,將可能導致CSRF攻擊。

如以下代碼片段用於銀行轉賬功能,若對於該重要敏感的操作沒有進行相應防護,將易於導致跨站請求偽造攻擊。

1     <form method="GET" action="/transferFunds " > 
2        cash: <input type="text" name="cash"> 
3        to: <input type=" text " name=“to"> 
4        <input type="submit" name="action" value="TransferFunds"> 
5     </form> 

修復方式

    (1)二次驗證,進行重要敏感操作時,要求用戶進行二次驗證。
    (2)驗證碼,進行重要敏感操作時,加入驗證碼。
    (3)在重要敏感操作的表單中加入隱藏的Token, 服務器端程序響應用戶請求前先驗證Token,判斷請求的合法性。

Cookie屬性

Cookie未設置httponly以及secure屬性.

1 Cookie cookie = new Cookie("userName",userName);
2 response.addCookie(cookie);

修復方式

1 Cookie cookie = new Cookie("userName",userName);
2 cookie.setSecure(true); // Secure flag
3 cookie.setHttpOnly(true);

Cookie生命周期

Cookie生命周期不應該超過一年.

1 Cookie cookie = new Cookie("email", email);
2 cookie.setMaxAge(60*60*24*365);

jsessionid

登錄前后改變jsessionid標識, 修改配置容器, 增強jsessionid算法邏輯.

1 HttpSession oldSession = req.getSession(false);
2 if (oldSession != null) {
3     //廢棄舊的session, 否則每次退出后再登錄, jsessionid不會變化.
4     oldSession.invalidate();
5 }
6 HttpSession session = req.getSession(true);

SecurityHeaders

配置更安全的HTTP Header

復制代碼
1             res.addHeader("X-Content-Type-Options", "nosniff");
2             res.addHeader("X-XSS-Protection", "1; mode=block");
3             res.addHeader("X-Frame-Options", "SAMEORIGIN");
4             res.addHeader("Content-Security-Policy", "object-src 'self'");
5 
6             res.addHeader("Cache-Control", "no-cache");
7             res.addHeader("Pragma", "no-cache");
8             res.addDateHeader("Expires", 0);
復制代碼

資源管理


日期格式化 

SimpleDateFormat 非線程安全的,parse()和format()方法包含一個可導致用戶看到其他用戶數據的race condition。

1 private static SimpleDateFormat dateFormat;

修復方式

使用ThreadLocal放置SimpleDateFormat或者同步鎖的方式.

訪問權限

程序未進行恰當的訪問權限控制,執行了一個包含用戶控制主鍵的SQL語句,可能會導致攻擊者訪問未經授權的記錄。
如下面代碼片段中的SQL語句用於查詢與指定標識符相匹配的清單。

1     id = Integer.decode(request.getParameter("invoiceID"));
2     String query = "SELECT * FROM invoices WHERE id = ?";
3     PreparedStatement stmt = conn.prepareStatement(query);
4     stmt.setInt(1, id);
5     ResultSet results = stmt.execute();

修復方式

先判斷當前用戶權限是否可以增刪數據, 可以通過把當前被授權的用戶名作為查詢語句的一部分來實現。 

復制代碼
1     userName = ctx.getAuthenticatedUserName();
2     id = Integer.decode(request.getParameter("invoiceID"));
3     String query = 
4         "SELECT * FROM invoices WHERE id = ? AND user = ?";
5     PreparedStatement stmt = conn.prepareStatement(query);
6     stmt.setString(1, id);
7     stmt.setString(2, userName);
8     ResultSet results = stmt.execute();
復制代碼

API限流

對於開放的API進行限流操作, 防止資源耗盡. 例如獲取IP城市 或者 天氣等等, 限制每個IP每小時最多調用1000次之類的.

簡單實現可以用計數器限流, 另外Guava提供了RateLimiter可以實現令牌桶算法限流.

復制代碼
1 RateLimiter limiter = caches.get(ip);
2  
3 if (limiter.tryAcquire()) {
4     System.out.println(i + " success " + new SimpleDateFormat("HH:mm:ss.sss").format(new Date()));
5 } else {
6     System.out.println(i + " failed " + new SimpleDateFormat("HH:mm:ss.sss").format(new Date()));
7 }
復制代碼

資源釋放

對於一些資源文件, 使用完畢后要在finally語句中進行釋放, 例如connection, 文件句柄, socket等等.

復制代碼
1         try {
2             DatabaseMetaData e = connection.getMetaData();
3             ResultSet rs1 = e.getTableTypes();
4             ......
5         } catch (SQLException e) {
6             return StringUtils.EMPTY;
7         } finally {
8             DBUtils.close(connection);
9         }
復制代碼

路徑遍歷

用程序對用戶可控制的輸入未經合理校驗,就傳送給一個文件API。攻擊者可能會使用一些特殊的字符(如“..”和“/”)擺脫受保護的限制,訪問一些受保護的文件或目錄。

1     String path = getInputPath();
2     if (path.startsWith("/safe_dir/")){
3         File f = new File(path);
4         f.delete()
5     }

攻擊者可能提供類似下面的輸入:/safe_dir/../important.dat

修復方式

使用白名單策略, 限制資源文件讀取和訪問.

路徑輸出

禁止輸出服務器絕對路徑到前端.

1         PrintWriter writer = WebUtils.createPrintWriter(res);
2         writer.write(file.getAbsolutePath());

修復方式

使用相對路徑

數據跨越信任邊界

數據從一個不可信賴域存儲到一個可信賴域導致程序錯誤信賴未驗證的數據。

1        String name = req.getParameter("userName");
2        HttpSession sess = req.getSession();
3        sess.setAttribute("user", name);

修復方式

數據跨越信任邊界時需要進行合理的驗證,保證信賴域中數據是安全的。

配置管理


Session失效配置

將Session的失效時間設置為30分鍾或更少,既能使用戶在一段時間內與應用程序互動,又提供了一個限制窗口攻擊的合理范圍。

修復方式

    <session-config>
        <session-timeout>30</session-timeout>
    </session-config>

錯誤頁面

Web應用程序的默認錯誤頁面不應顯示程序的敏感信息。Web應用程序應該為4xx(如404)錯誤、5xx(如503)錯誤、java.lang.Throwable異常定義一個錯誤頁面,防止攻擊者挖掘應用程序容器內置錯誤響應信息。報錯頁面中不應該包含類名, 方法名, 執行堆棧等信息.

修復方式

應用程序應該在web.xml中配置默認的錯誤頁面。

復制代碼
    <error-page>
        <error-code>403</error-code>
        <location>/common/403.jsp</location>
    </error-page>
    <error-page>
        <error-code>404</error-code>
        <location>/common/404.jsp</location>
    </error-page>
    <error-page>
        <error-code>500</error-code>
        <location>/common/500.jsp</location>
    </error-page>
    <error-page>
        <exception-type>java.lang.Throwable</exception-type>
        <location>/common/error.jsp</location>
    </error-page>
復制代碼

不安全的SSLContext

1      SSLContext.getInstance("SSL");

修復方式

配置web容器使用更安全的TLSv1.2協議.

1      SSLContext.getInstance("TLS");

未加密的Socket

1         ServerSocket soc = new ServerSocket(1234);
2         ......
3         Socket soc = new Socket("www.google.com",80);
4         ......

修復方式

1         ServerSocket soc = SSLServerSocketFactory.getDefault().createServerSocket(1234);
2         ......
3         Socket soc = SSLSocketFactory.getDefault().createSocket("www.google.com", 443);
4         ......

不安全的FTP協議

代碼中使用SFTP替代FTP

1          Channel channel = session.openChannel("sftp");  
2          channel.connect();  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM