Kie*_*lly 14 java mysql sql security jdbc
是否存在类似于PHP的mysql_real_escape_string()的Java?
这是为了在将它们传递给Statement.execute()之前逃避SQL注入尝试.
我知道我可以使用PreparedStatement,但我们假设这些是一次性语句,因此准备它们会导致性能降低.我已经将代码更改为使用PreparedStatement,但考虑到现有代码的结构,escape()函数会使代码更改更容易查看和维护; 我更喜欢易于维护代码,除非有一个令人信服的理由来增加复杂性.此外,PreparedStatements由数据库以不同方式处理,因此这可能使我们暴露于数据库中我们之前未遇到过的错误,在发布到生产之前需要进行更多测试.
Apache StringEscapeUtils escapeSQL()仅转义单引号.
后记:在我继承的环境中存在许多微妙之处,我在我的问题中故意避免.
需要考虑的两点:
1)准备好的语句不是灵丹妙药,也不能提供100%的SQL注入保护.某些数据库驱动程序使用不安全的字符串连接实例化参数化查询,而不是将查询预编译为二进制形式.此外,如果您的SQL依赖于存储过程,则需要确保存储过程本身不会以不安全的方式构建查询.
2)大多数预准备语句实现将语句绑定到语句被实例化的数据库连接上.如果您正在使用数据库连接池,则需要注意
仅使用准备好的语句引用与其准备的连接.一些池化机制确实透明地实现了这一点.否则,您也可以汇集预准备语句或(最简单但更多开销)为每个查询创建一个新的预准备语句.
Dan*_*ler 12
据我所知,没有"标准"的方法来做到这一点.
尽管你目前担心,我强烈建议使用准备好的陈述.性能影响可以忽略不计 - 我们有类似的情况,每秒有几千个语句 - 其中大多数也是一次性的.
您获得的安全性应该比您尚未看到的性能问题高得多.在我看来,这是"不要过早优化"的明确情况.
在任何情况下,如果你真的发现你遇到了性能问题,请确保准备好的语句真的是通过仔细分析然后寻找替代方案的原因.直到那时你应该省去试图逃避正确的麻烦.
这更为重要,因为我推断您正在开发某种面向公众的网站 - 内部应用程序很少获得足够的流量来关注性能.
这里有一些代码可以实现您的目标.最初是在Vnet Publishing wiki上.
/**
* Mysql Utilities
*
* @author Ralph Ritoch <rritoch@gmail.com>
* @copyright Ralph Ritoch 2011 ALL RIGHTS RESERVED
* @link http://www.vnetpublishing.com
*
*/
package vnet.java.util;
public class MySQLUtils {
/**
* Escape string to protected against SQL Injection
*
* You must add a single quote ' around the result of this function for data,
* or a backtick ` around table and row identifiers.
* If this function returns null than the result should be changed
* to "NULL" without any quote or backtick.
*
* @param link
* @param str
* @return
* @throws Exception
*/
public static String mysql_real_escape_string(java.sql.Connection link, String str)
throws Exception
{
if (str == null) {
return null;
}
if (str.replaceAll("[a-zA-Z0-9_!@#$%^&*()-=+~.;:,\\Q[\\E\\Q]\\E<>{}\\/? ]","").length() < 1) {
return str;
}
String clean_string = str;
clean_string = clean_string.replaceAll("\\\\", "\\\\\\\\");
clean_string = clean_string.replaceAll("\\n","\\\\n");
clean_string = clean_string.replaceAll("\\r", "\\\\r");
clean_string = clean_string.replaceAll("\\t", "\\\\t");
clean_string = clean_string.replaceAll("\\00", "\\\\0");
clean_string = clean_string.replaceAll("'", "\\\\'");
clean_string = clean_string.replaceAll("\\\"", "\\\\\"");
if (clean_string.replaceAll("[a-zA-Z0-9_!@#$%^&*()-=+~.;:,\\Q[\\E\\Q]\\E<>{}\\/?\\\\\"' ]"
,"").length() < 1)
{
return clean_string;
}
java.sql.Statement stmt = link.createStatement();
String qry = "SELECT QUOTE('"+clean_string+"')";
stmt.executeQuery(qry);
java.sql.ResultSet resultSet = stmt.getResultSet();
resultSet.first();
String r = resultSet.getString(1);
return r.substring(1,r.length() - 1);
}
/**
* Escape data to protected against SQL Injection
*
* @param link
* @param str
* @return
* @throws Exception
*/
public static String quote(java.sql.Connection link, String str)
throws Exception
{
if (str == null) {
return "NULL";
}
return "'"+mysql_real_escape_string(link,str)+"'";
}
/**
* Escape identifier to protected against SQL Injection
*
* @param link
* @param str
* @return
* @throws Exception
*/
public static String nameQuote(java.sql.Connection link, String str)
throws Exception
{
if (str == null) {
return "NULL";
}
return "`"+mysql_real_escape_string(link,str)+"`";
}
}
Run Code Online (Sandbox Code Playgroud)
不要认为PreparedStatements较慢.试一试,测量它,然后判断.
PreparedStatements应始终优先于Statement使用,几乎毫无例外,尤其是当您正在尝试避免SQL注入攻击时.
| 归档时间: |
|
| 查看次数: |
13626 次 |
| 最近记录: |