SQL查詢語句注入,來自用戶的數據經過字符串拼接的方式構築到SQL語句中。sql
使用帶佔位符的預編譯執行方式的SQL語句,而且,全部非程序自身的數據都不參與SQL語句的構成。數據庫
如:app
public void SQL_Injection(HttpServletRequest request, Connection c){性能
String text = request.getParameter("text");spa
Statement s = c.createStatement();命令行
String sql = "select * from table where 1 = 1";xml
s.executeQuery(sql + " and a = '" + text + "'");對象
}資源
修復爲:字符串
public void SQL_Injection_Fix(HttpServletRequest request, Connection c){
String text = request.getParameter("text");
String sql = "select * from table where 1 = 1 and a = ?";
PreparedStatement s = c.preparedStatement(sql);
s.setString(1, text);
s.executeQuery();
}
二次SQL注入,來自數據庫的數據經過字符串拼接的方式構築到SQL語句中。
使用帶佔位符的預編譯執行方式的SQL語句,而且,全部非程序自身的數據都不參與SQL語句的構成。
如:
public void SQL_Injection(HttpServletRequest request, Connection c){
String text = request.getParameter("text");
Statement s = c.createStatement();
String sql = "select * from table where 1 = 1";
s.executeQuery(sql + " and a = '" + text + "'");
}
修復爲:
public void SQL_Injection_Fix(HttpServletRequest request, Connection c){
String text = request.getParameter("text");
String sql = "select * from table where 1 = 1 and a = ?";
PreparedStatement s = c.preparedStatement(sql);
s.setString(1, text);
s.executeQuery();
}
代碼注入,來自用戶的數據被用做程序代碼執行。
全部程序外來數據都不要用做代碼、反射使用。不要動態去構造對象。
如:String methodName = request.getParameter(「CbData.SYNC_METO」);
……
Method syncMethod = dataSynClazz.getMethod(methodName,null);
修復爲:
String methodName = request.getParameter(「CbData.SYNC_METO」);
private Map<String,Method> methodPool = new HashMap<String,Method>();
Method syncMethod = methodPool.get(methodName);
如:public Object getInstance(String className) throws Exception{
Class<?> clazz = Class.forName(className);
return clazz.newInstance();
}
修復爲:
Private Map<String,Class<?>> classPool = new HashMap<String,Class<?>>();
{
classPool.put(「UserClass」,userClass.class);
}
Public Object getInstance(String className) throws Exception{
Class<?> clazz = classPool.get(className);
return clazz.newInstance();
}
鏈接字符串注入,來自用戶的數據被用做鏈接字符命令。
全部程序外來數據都不要用做鏈接字符串、反射使用,若要使用可以使用配置方式。
命令行注入,用戶可控的數據被直接做爲系統命令在命令行執行。
使用封裝類,枚舉限制可被執行的命令。
如:
public class CommandLine_Injection{
public static void main(String[] args){
StringBuffer sb = new StringBuffer();
if(args != null){
for(String arg : args){
sb.append(arg + " ");
}
}
try {
Runtime.getRuntime().exec(sb.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
}
修復爲:
public class CommandLine_Injection{
public static void main(String[] args){
WindowsCmd wc = new NotepadCmd(args);
if(wc.isValid()){
try {
Runtime.getRuntime().exec(wc.getCommandLineString());
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public interface WindowsCmd{
String getCommandLineString();
boolean isValid();
}
public class NotepadCmd implements WindowsCmd{
private static final String head = "notepad";
//Java中的正則執行引擎存在性能問題,可以使用字符串處理方式校驗。
private static final String fileRegex = "[a-zA-Z]:/(([^/\\t\\*<>\\?\\|:\"])+/)*([^/\\t\\*<>\\?\\|:\"])+";
public NotepadCmd(String[] args){
valid = false;
if(args != null && args.length >= 2){
String aName = args[0];
String fName = args[1];
aName = aName.toLowerCase();
if(head.equals(aName)){
if("".equals(fName.replaceAll(fileRegex, ""))){
fileName = fName;
valid = true;
}
}
}
}
private String fileName;
private boolean valid;
public String getFileName(){
return fileName;
}
public boolean isValid(){
return valid;
}
public String getCommandLineString(){
return new String(head) + " " + getFileName();
}
}
資源注入,程序接收客戶端輸入數據,但在輸入被用做一個可能超出預期控制範圍的資源的標識符以前,不對該輸入進行限制或過濾。
使用正確的黑名單和白名單組合去確保系統只對有效的、預期的輸入進行處理。
LDAP注入,程序沒有足夠過濾在LDAP查詢和響應中的有害字符,從而容許攻擊者注入特定字符去修改LDAP查詢的語法、內容和命令。
假設全部輸入都是惡意的。使用合適的黑名單和白名單組合來過濾或引用來自於用戶控制輸入數據的LDAP句法。
context = new InitialDirContext(env);
String searchFilter = "StreetAddress=" + address;
NamingEnumeration answer = context.search(searchBase, searchFilter, searchCtls);
用戶輸入數據(地址)在被用於構建LDAP查詢前沒有被正確驗證。應當對address進行黑名單和白名單過濾驗證。
XPath注入,使用客戶端輸入數據,構造一個XPath表達式從xml中檢索數據,但並未對用戶可控的輸入數據進行過濾。
使用參數化的XPath查詢。過濾用戶輸入的數據並對數據進行轉義。