开发:
SQL
注入是一种数据库攻击手段。攻击者通过向应用程序提交恶意代码来改变原
SQL
语句的含义,
进而执行任意
SQL
命令,达到入侵数据库乃至操作系统的目的。
例如:下面代码片段中,动态构造并执行了一个
SQL
查询来认证用户。
public void doPrivilegedAction( String username, char[] password) throws SQLException {
Connection connection = getConnection();
if (connection == null) {
// handle error
}
try {
String pwd = hashPassword(password);
String sqlString = "SELECT * FROM db_user WHERE username = '" + username + "' AND password
= '" + pwd + "'";
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery(sqlString);
if (!rs.next()) {
throw new SecurityException( "User name or password incorrect");
}
// Authenticated; proceed
} finally {
try {
connection.close();
} catch (SQLException x) {
// forward to handler
}
}
}
如果攻击者能够替代
username
和
password
中的任意字符串,它们可以使用下面的关于
username
的字
符串进行
SQL
注入。
validuser' OR '1'='1
当其注入到命令时,命令就会变成:
SELECT * FROM db_user WHERE username=’validuser' OR '1'='1' AND password=’’
同样,攻击者可以为
password
提供如下字符串。
' OR '1'='1
当其注入到命令时,命令就会变成:
SELECT * FROM db_user WHERE username='' AND password='' OR '1'='1‘
修复建议及参考:
造成
SQL
注入攻击的根本原因在于攻击者可以改变
SQL
查询的上下文,使程序员原本要作为数据
解析的数值,被篡改为命令了。防止
SQL
注入的方法如下:
(
1
)正确使用参数化
API
进行
SQL
查询。
(
2
)如果构造
SQL
指令时需要动态加入约束条件,可以通过创建一份合法字符串列表,使其对应于可
能要加入到
SQL
指令中的不同元素,来避免
SQL
注入攻击。
例 如 : 以 下 代 码 片 段 使 用
java.sql.PreparedStatement
代 替
java.sql.Statement
, 在
java.sql.PreparedStatement
类中可以对输入字符串进行转义,如果使用正确的话,可以防止
SQL
注入。
public void doPrivilegedAction(String username, char[] password) throws SQLException {
Connection connection = getConnection();
if (connection == null) {
// Handle error
}
try {
String pwd = hashPassword(password);
// Ensure that the length of user name is legitimate
if ((username.length() > 8) {
// Handle error
}
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();
if (!rs.next()) {
throw new SecurityException("User name or password incorrect");
}
// Authenticated, proceed
} finally {
try {
connection.close();
} catch (SQLException x) {
// forward to handler
}
}
}