本節書摘來異步社群《java編碼指南:編寫安全可靠程式的75條建議》一書中的第1章,第1.7節,作者:【美】fred long(弗雷德•朗), dhruv mohindra(德魯•莫欣達), robert c.seacord(羅伯特 c.西科德), dean f.sutherland(迪恩 f.薩瑟蘭), david svoboda(大衛•斯沃博達),更多章節内容可以通路雲栖社群“異步社群”公衆号檢視。
當有不可信的輸入注入動态構造的代碼中時,會引起代碼注入攻擊。一個明顯的潛在漏洞是在java代碼中使用javascript代碼。javax.script包定義了java腳本引擎的接口和類,以及在java代碼中使用這些接口和類的架構。javax.script api的濫用,會導緻攻擊者在目标系統上執行任意代碼。
這條指南是《the cert® oracle® secure coding standard for java™》[long 2012]的“ids00-j. sanitize untrusted data passed across a trust boundary”的一個執行個體。
下面的違規代碼示例将不可信的使用者輸入嵌入了負責列印輸入的javascript語句中。
dummy');
var bw = new javaimporter(java.io.bufferedwriter);
var fw = new javaimporter(java.io.filewriter);
with(fw) with(bw) {
bwr = new bufferedwriter(new filewriter("config.cfg"));
bwr.write("some text"); bwr.close();
}
// ;<code>`</code>
這個示例中的腳本首先列印“dummy”,然後将“some text”寫入一個名為config.cfg的配置檔案中。這是一個可以導緻任意代碼執行的真實漏洞。
最好的防禦代碼注入漏洞的方式就是阻止包含可執行代碼的使用者輸入。任何用于動态代碼的使用者輸入,都必須進行無害化處理,例如,確定使用者輸入隻包含白名單裡的有效字元。最好是在資料輸入後,通過使用用于存儲和處理資料的提取方法,立即執行資料無害化處理。更多細節請參考“ids00-j. sanitize untrusted data passed across a trust boundary”[long 2012]。如果使用者名中必須包含某些特殊字元,那麼必須先對它們進行标準化,然後再對它們進行表單輸入驗證處理。下面的合規解決方案使用了白名單來防止腳本引擎對未經處理的輸入進行解析。
class acc {
private static class restrictedaccesscontrolcontext {
private static final accesscontrolcontext instance;
static {
instance =
new accesscontrolcontext(
new protectiondomain[] {
new protectiondomain(null, null) // no permissions
});
}
}
private static void evalscript(final string firstname)
throws scriptexception {
scriptenginemanager manager = new scriptenginemanager();
final scriptengine engine =
manager.getenginebyname("javascript");
// restrict permission using the two-argument
// form of doprivileged()
try {
accesscontroller.doprivileged(
new privilegedexceptionaction
public object run() throws scriptexception {
engine.eval("print('" + firstname + "')");
return null;
}
},
// from nested class
restrictedaccesscontrolcontext.instance);
} catch (privilegedactionexception pae) {
// handle error
}
}<code>`</code>
将這個方法和白名單結合在一起使用,可以獲得更高的安全性。
未能防止代碼注入可能導緻任意代碼的執行。