java开发安全之:Password Management: Hardcoded Password

Overview

Hardcoded password 可能会削弱系统安全性,一旦出现安全问题将无法轻易修正。

Details

使用硬编码方式处理密码绝非好方法。这不仅是因为所有项目开发人员都可以使用通过硬编码方式处理的密码,而且还会使解决这一问题变得极其困难。在代码投入使用之后,除非对软件进行修补,否则将无法更改密码。如果受密码保护的帐户遭受入侵,系统所有者将必须在安全性和可用性之间做出选择。 在这种情况下, getConnection() 的调用中发现 Hardcoded Password。

例 1:以下代码用 hardcoded password 来连接数据库:

DriverManager.getConnection(url, "scott", "tiger");

该代码可以正常运行,但是有权访问该代码的任何人都能得到这个密码。一旦程序发布,除非修补该程序,否则可能无法更改数据库用户“scott”和密码“tiger”。雇员可以利用手中掌握的信息访问权限入侵系统。

更糟的是,如果攻击者能够访问应用程序的字节代码,那么他们就可以利用 javap -c 命令访问已经过反汇编的代码,而这些代码中恰恰包含用户使用过的密码值。此操作的结果可能类似于

Example 1 的以下内容:

javap -c ConnMngr.class 22: ldc #36; //String 
jdbc:mysql://ixne.com/rxsql 24: ldc #38; //String scott 26: ldc #17; //String tiger

在移动环境中,由于设备丢失的几率较高,所以 password management 非常重要。

示例 2:以下代码会使用硬编码的用户名和密码设置用于通过 Android WebView 查看受保护页面的身份验证。 ...

webview.setWebViewClient(new WebViewClient() 
{ 
public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {
 handler.proceed("guest", "allow"); 
} 
}
); 

... 与Example 1 类似,该代码可以正常运行,但是有权访问此代码的任何人都可以获得此密码。

Recommendations

绝不能对密码进行硬编码。通常情况下,应对密码进行模糊处理,并在外部资源文件中进行管理。在系统中的任何位置采用明文的形式存储密码,会造成任何有足够权限的人均可读取和无意中误用密码。至少,要对密码进行散列处理后再存储。 一些第三方产品声称可以安全地管理密码。例如,WebSphere Application Server 4.x 用简单的异或加密算法加密数值,但是请不要对诸如此类的加密方式给予完全的信任。

WebSphere 以及其他一些应用服务器通常都只提供过期的且相对较弱的加密机制,这对于对安全性要求较高的环境来说是远远不够的。目前,最佳的安全且通用的解决方法是创建自己的专有机制。 对于 Android 以及其他任何使用 SQLite 数据库的平台来说,SQLCipher 是一个不错的备选方案。SQLCipher 是对 SQLite 数据库的扩展,为数据库文件提供了透明的 256 位 AES 加密。因此,凭证可以存储在加密的数据库中。

示例 3:以下代码演示了如何在下载必要的二进制文件后将 SQLCipher 集成到 Android 应用程序中,并将凭据存储到数据库文件中。

import net.sqlcipher.database.SQLiteDatabase; 
 SQLiteDatabase.loadLibs(this); 
File dbFile = getDatabasePath("credentials.db"); 
dbFile.mkdirs(); 
dbFile.delete(); 
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(dbFile, "credentials", null); db.execSQL("create table credentials(u, p)"); 
db.execSQL("insert into credentials(u, p) values(?, ?)", new Object[]{username, password}); 

... 请注意,对 android.database.sqlite.SQLiteDatabase 的引用可以使用 net.sqlcipher.database.SQLiteDatabase 代替。 要在 WebView 存储器上启用加密,必须使用 sqlcipher.so 库重新编译 WebKit。