赞
踩
命令注入是指,在应用程序执行的命令中包含来源于不可信数据时,程序本身没有对这些不可信数据做正确、合理的验证和过滤,导致系统执行恶意命令。
例1:以下代码通过Runtime.exec()
方法调用Windows的dir命令,列出目录列表。
package com.syn;
import java.io.*;
public class DirList {
public static void main(String[] args) {
String dir = System.getProperty("dir");
Process process = null;
InputStream istream = null;
try {
process = Runtime.getRuntime().exec("cmd.exe /c dir" + dir);
int result = process.waitFor();
if (result != 0) {
System.out.println("process error: " + result);
}
istream = (result == 0) ? process.getInputStream() : process.getErrorStream();
byte[] buffer = new byte[512];
while (istream.read(buffer) != -1) {
System.out.print(new String(buffer, "gb2312"));
}
} catch (IOException e1) {
e1.printStackTrace();
} catch (InterruptedException e2) {
e2.printStackTrace();
} finally {
if (istream != null) {
try {
istream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (process != null) {
process.destroy();
}
}
}
}
攻击者可以构造特殊命令参数来利用该程序,例如:
java -Ddir="..\\ & shutdown -s -t 60" DirList
上面的命令实际上执行下面两条命令:
cmd.exe /c dir ..\ & shutdown -s -t 60
例2:以下代码片段来自一个Web应用程序,它该段代码通过运行rmanDB.bat脚本启动Oracle数据库备份,然后运行cleanup.bat脚本删除一些临时文件。脚本文件rmanDB.bat接受一个命令行参数,指明需要执行的备份类型。
...
String btype = request.getParameter("backuptype");
String cmd = new String("cmd.exe /K \"c:\\util\\rmanDB.bat "+btype+"&& c:\\utl\\cleanup.bat\"");
System.Runtime.getRuntime().exec(cmd);
...
该段代码没有对来自用户请求中的参数做任何校验。
通常情况下,Runtime.exec()
函数不会执行多条命令,但在以上代码中,为了执行多条命令,程序调用Runtime.exec()
方法,首先运行了cmd.exe指令,因此能够执行用&&分隔的多条命令了。如果攻击者传递了一个形式为&& del c:\\dbms\\*.*
的字符串,那么该段代码将会在执行其他指定命令的同时执行这条命令。
例3:下面是利用Apache Axis框架搭建的WebService的源码片段。
public String getResponse(String endpoint) {
Service service = new Service();
Call call = (Call) service.createCall();
call.setTargetEndpointAddress(new URL(endpoint));
call.setOperation("list");
...
}
在搭建的Axis 1.4+Tomcat6的环境,将AdminService配置中的enableRemoteAdmin
属性设置为true时,如果上面提供访问WebService的字符串变量endpoint
是受外部可控的,那么攻击者很可能利用精心设计的字符串作为endpoint的输入值,从而构造出包含注入命令的SOAP请求协议,进而实施命令注入攻击。
修复建议:
防止命令注入的方法如下:
例1:下面代码片段中,使用正则表达式匹配用户的输入。
...
if (!Pattern.matches("[0-9A-Za-z@.]+", dir)) {
// Handle error
}
...
例2:下面代码片段中,通过只向Runtime.exec()
方法输入那些受信的字符串来防止命令注入。
...
String btype = null;
// only allow integer choices
int number = Integer.parseInt(request.getParameter("backuptype"));
switch (number) {
case 1:
btype = "tables"
break; // Option 1
case 2:
btype = "users"
break; // Option 2
case 3:
btype = "full"
break; // Option 3
default: // invalid
break;
}
if (btype == null) {
// handle error
}
...
程序从一个不可信赖的数据源获取数据,未进行验证就置于HTTP头文件中发给用户,可能会导致HTTP响应截断攻击。
例如:下列代码片段中,程序从HTTP请求中获取author
的值,并将其设置到HTTP响应文件的cookie中。
...
String author = request.getParameter(AUTHOR_PARAM);
...
Cookie cookie = new Cookie("author", author);
cookie.setMaxAge(cookieExpiration);
response.addCookie(cookie);
...
如果请求中提交的是一个Jane Smith
字符串,那么包含该cookie的HTTP响应可能表现为以下形式:
HTTP/1.1 200 OK
...
Set-Cookie: author=Jane Smith
...
那么如果攻击者提交的是一个恶意字符串,比如Wiley Hacker\r\nHTTP/1.1 200 OK\r\n...
,那么HTTP响应就会被分割成以下形式的两个响应:
HTTP/1.1 200 OK
...
Set-Cookie: author=Wiley Hacker
HTTP/1.1 200 OK
...
这样第二个响应已完全由攻击者控制,攻击者可以用所需的头文件和正文内容构建该响应实施攻击。
修复建议
防止HTTP响应截断攻击的最安全的方法是创建一份安全字符白名单,只接受完全由这些受认可的字符组成的输入出现在HTTP响应头文件中。
例如:以下代码片段中,验证了author
的值是否由标准的字母数字字符组成。
...
String author = request.getParameter(AUTHOR_PARAM);
if (Pattern.matches("[0-9A-Za-z]+", author)) {
...
Cookie cookie = new Cookie("author", author);
cookie.setMaxAge(cookieExpiration);
response.addCookie(cookie);
}
...
SQL注入是一种数据库攻击手段。攻击者通过向应用程序提交恶意代码来改变原SQL语句的含义,进而执行任意SQL命令,达到入侵数据库乃至操作系统的目的。在Mybatis Mapper Xml中,#
变量名称创建参数化查询SQL语句,不会导致SQL注入。而$
变量名称直接使用SQL指令,而$
变量名称直接使用SQL指令,将会存在一定风险,当SQL指令所需的数据来源于不可信赖的数据源时,可能会导致SQL注入。
例如:以下代码片段采用$
变量名称动态地构造并执行了SQL查询。
<!--select user information by name-->
<select id="queryByUserName" resultMap="userResultMap" parameterType="String">
select * from db_user where user_name=${username}
</select>
如果攻击者能够替代username中的任意字符串,它们可以使用下面的关于username的字符串进行SQL注入。
validuser' OR '1'='1
当其注入到命令时,命令就会变成:
select * from db_user where user_name ='validuser' OR '1'='1'
。即使所输入字符串不是来源于不可信赖的数据源,程序仍然存在着一定风险。
修复建议:
造成SQL注入攻击的根本原因在于攻击者可以改变SQL查询的上下文,使程序员原本要作为数据解析的数值,被篡改为命令了。防止SQL注入的方法如下:
#
变量名称,创建参数化查询SQL语句。<!--select user information by name-->
<select id="queryByUserName" resultMap="userResultMap" parameterType="String">
select * from db_user where user_name=#{username}
</select>
SQL注入是一种数据库攻击手段。攻击者通过向应用程序提交恶意代码来改变原SQL语句的含义,进而执行任意SQL命令,达到入侵数据库乃至操作系统的目的。
例如:下面代码片段中,动态构造并执行了一个SQL查询来认证用户。
public void doPrivilegedAction(HttpServletRequest request, char[] password) throws SQLException {
Connection connection = getConnection();
if (connection == null) {
// handle error
}
try {
String username = request.getParameter("username");
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注入的方法如下:
java.sql.PreparedStatement
代替java.sql.Statement
,在java.sql.PreparedStatement
类中可以对输入字符串进行转义,如果使用正确的话,可以防止SQL注入。public void doPrivilegedAction(HttpServletRequest request, char[] password) throws SQLException {
Connection connection = getConnection();
if (connection == null) {
// handle error
}
try {
String username = request.getParameter("username");
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
}
}
}
SQL注入是一种数据库攻击手段。攻击者通过向应用程序提交恶意代码来改变原SQL语句的含义,进而执行任意SQL命令,达到入侵数据库乃至操作系统的目的。在Mybatis Mapper Xml中,#
变量名称创建参数化查询SQL语句,不会导致SQL注入。而$
变量名称直接使用SQL指令,会导致SQL注入攻击。
例如:以下代码片段采用$
变量名称动态地构造并执行了SQL查询。
<!--select user information by name-->
<select id="queryByUserName" resultMap="userResultMap" parameterType="String">
select * from db_user where user_name=${username}
</select>
用户调用以下命令时:
String username = request.getParameter("name");
user.queryByUserName(username);
如果攻击者能够替代username
中的任意字符串,它们可以使用下面的关于username
的字符串进行SQL注入。
validuser' OR '1'='1
当其注入到命令时,命令就会变成:
select * from db_user where user_name ='validuser' OR '1'='1'
修复建议
造成SQL注入攻击的根本原因在于攻击者可以改变SQL查询的上下文,使程序员原本要作为数据解析的数值,被篡改为命令了。防止SQL注入的方法如下:
#
变量名称,创建参数化查询SQL语句。<!--select user information by name-->
<select id="queryByUserName" resultMap="userResultMap" parameterType="String">
select * from db_user where user_name=#{username}
</select>
SQL注入是一种数据库攻击手段。攻击者通过向应用程序提交恶意代码来改变原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'
修复建议
常见的修复方法:
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
}
}
}
存储型XSS是指应用程序通过Web请求获取不可信赖的数据,并且在未检验数据是否存在XSS代码的情况下,将其存入数据库。当程序下一次从数据库中获取该数据时,致使页面再次执行XSS代码。存储型XSS可以持续攻击用户,在用户提交了包含XSS代码的数据存储到数据库后,每当用户在浏览网页查询对应数据库中的数据时,那些包含XSS代码的数据就会在服务器解析并加载,当浏览器读到XSS代码后,会当做正常的HTML和JS解析并执行,于是发生存储型XSS攻击。
例如:下面JSP代码片段的功能是根据一个已知用户雇员ID(id)从数据库中查询出该用户的地址,并显示在JSP页面上。
<%
...
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select * from users where id =" + id);
String address = null;
if (rs != null) {
rs.next();
address = rs.getString("address");
}
%>
家庭地址: <%= address %>
如果address的值是由用户提供的,且存入数据库时没有进行合理的校验,那么攻击者就可以利用上面的代码进行存储型XSS攻击。
修复建议:
为了避免存储型XSS攻击,建议采用以下方式进行防御:
1.对从数据库或其它后端数据存储获取不可信赖的数据进行合理验证(如年龄只能是数字),对特殊字符(如<、>、'、"
以及<script>、javascript
等进行过滤。
2.根据数据将要置于HTML上下文中的不同位置(HTML标签、HTML属性、JavaScript脚本、CSS、URL),对所有不可信数据进行恰当的输出编码。
例如:采用OWASP ESAPI对数据输出HTML上下文中不同位置,编码方法如下。
//HTML encode
ESAPI.encoder().encodeForHTML(inputData);
//HTML attribute encode
ESAPI.encoder().encodeForHTMLAttribute(inputData);
//JavaScript encode
ESAPI.encoder().encodeForJavaScript(inputData);
//CSS encode
ESAPI.encoder().encodeForCSS(inputData);
//URL encode
ESAPI.encoder().encodeForURL(inputData);
3.设置HttpOnly属性,避免攻击者利用跨站脚本漏洞进行Cookie劫持攻击。在Java EE中,给Cookie添加HttpOnly的代码如下:
...
response.setHeader("Set-Cookie","cookiename=cookievalue; path=/; Domain=domainvaule; Max-age=seconds; HttpOnly");
...
反射型XSS是指应用程序通过Web请求获取不可信赖的数据,并在未检验数据是否存在恶意代码的情况下,将其发送给用户。反射型XSS一般可以由攻击者构造带有恶意代码参数的URL来实现,在构造的URL地址被打开后,其中包含的恶意代码参数被浏览器解析和执行。这种攻击的特点是非持久化,必须用户点击包含恶意代码参数的链接时才会触发。
例如:下面JSP代码片段的功能是从HTTP请求中读取输入的用户名(username)并显示到页面。
<%
String name= request.getParameter("username"); %>
...
姓名: <%= name%>
...
如果name里有包含恶意代码,那么Web浏览器就会像显示HTTP响应那样执行该代码,应用程序将受到反射型XSS攻击。
修复建议
为了避免反射型XSS攻击,建议采用以下方式进行防御:
1.对用户的输入进行合理验证(如年龄只能是数字),对特殊字符(如<、>、'、"
以及<script>、javascript
等进行过滤。
2.根据数据将要置于HTML上下文中的不同位置(HTML标签、HTML属性、JavaScript脚本、CSS、URL),对所有不可信数据进行恰当的输出编码。
例如:采用OWASP ESAPI对数据输出HTML上下文中不同位置,编码方法如下。
//HTML encode
ESAPI.encoder().encodeForHTML(inputData);
//HTML attribute encode
ESAPI.encoder().encodeForHTMLAttribute(inputData);
//JavaScript encode
ESAPI.encoder().encodeForJavaScript(inputData);
//CSS encode
ESAPI.encoder().encodeForCSS(inputData);
//URL encode
ESAPI.encoder().encodeForURL(inputData);
3.设置HttpOnly属性,避免攻击者利用跨站脚本漏洞进行Cookie劫持攻击。在Java EE中,给Cookie添加HttpOnly的代码如下:
...
response.setHeader("Set-Cookie","cookiename=cookievalue; path=/; Domain=domainvaule; Max-age=seconds; HttpOnly");
...
应用程序允许未验证的用户输入控制重定向中的URL,攻击通过构建URL,使用户重定向到任意URL,利用这个漏洞可以诱使用户访问某个页面,挂马、密码记录、下载任意文件等,常被用来钓鱼。
例如:以下Servlet代码会接收前台的url参数,然后Servlet进行一系列业务操作后重定向到该链接,一般情况下这个链接可能是默认的,例如登陆处登陆成功后跳到首页,但是这种情况没有限制用户输入自定义的链接。
public class RedirectServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,IOException{
...
String query = request.getQueryString();
if (query.contains("url")) {
String url = request.getParameter("url");
response.sendRedirect(url);
}
}
}
常见的场景是受害者收到一封电子邮件,指示该用户打开http://trusted.example.com/ecommerce/redirect.asp?url=www.wilyhacker.com
链接,用户有可能会打开该链接,因为他会认为这个链接将转到可信赖的站点。然而,一旦用户打开该链接,上面的代码会将浏览器重定向至http://www.wilyhacker.com
。很多用户都被告知,要始终监视通过电子邮件收到的URL,以确保链接指向一个他们所熟知的可信赖站点。尽管如此,如果攻击者对目标URL进行16进制编码:http://trusted.example.com/ecommerce/redirect.asp?url=%77%69%6C%79%68%61%63%6B%65%72%2E%63%6F%6D
以提高用户辨别URL的难度。更糟糕的是像这样的url通过例如QQ等程序进行传输的时候,这些程序的安全机制是不能识别url参数中的危险链接的。
修复建议
防止重定向漏洞的方法是创建一份合法URL列表,用户只能从中进行选择,进行重定向操作。
例如:以下Servlet代码先对url进行判断,再决定是否重定向到该链接。
public class RedirectServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,IOException{
...
String query = request.getQueryString();
if (query.contains("url")) {
String url = request.getParameter("url");
if(safeUrls.contains(url)){
response.sendRedirect(url);
}
...
}
}
}
应用程序对用户可控制的输入未经合理校验,就传送给一个文件API。攻击者可能会使用一些特殊的字符(如..
和/
)摆脱受保护的限制,访问一些受保护的文件或目录。
例如:下面代码片段通过验证输入路径是否以/safe_dir/
为开头,来判断是否进行创建、删除操作。
...
String path = getInputPath();
if (path.startsWith("/safe_dir/")){
File f = new File(path);
f.delete()
}
...
攻击者可能提供类似下面的输入:
/safe_dir/../important.dat
程序假定路径是有效的,因为它是以/safe_dir/
开头的,但是../
将导致程序删除important.dat
文件的父目录。
修复建议:
预防路径遍历的威胁,有以下三种方法:
Java API中提供了java.util.Random
类实现PRNG()
,该PRNG是可移植和可重复的,如果两个java.util.Random
类的实例使用相同的种子,会在所有Java实现中生成相同的数值序列。
例如:下面代码片段中,使用了java.util.Random
类,该类对每一个指定的种子值生成同一个序列。
import java.util.Random;
// ...
public static void main (String args[]) {
// ...
for (int i = 0; i < 10; i++) {
Random random = new Random(123456);
int number = random.nextInt(21);
...
}
}
修复建议:
在安全性要求较高的应用中,应使用更安全的随机数生成器,如java.security.SecureRandom
类。
例如:下面代码片段中,使用java.security.SecureRandom
来生成更安全的随机数。
import java.security.SecureRandom;
import java.security.NoSuchAlgorithmException;
// ...
public static void main (String args[]) {
try {
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
for (int i = 0; i < 10; i++) {
int number = random.nextInt(21);
...
}
} catch (NoSuchAlgorithmException nsae) {
...
}
}
程序中采用硬编码方式处理密码,一方面会降低系统安全性,另一方面不易于程序维护。
例如:下列代码中采用硬编码方式处理密码。
public class ConnectionConfig{
String url = "localhost";
String name = "admin";
String password = "123456";
...
}
修复建议:
程序中不应对密码进行硬编码,可以使用配置文件或数据库存储的方式来存储系统所需的数据;并且录入数据时,还可以在对敏感数据做加密处理之后再进行数据的录入。
例如:下列代码中从配置文件中获取经过加密的密码值并解密使用。
public class ConnectionConfig{
String url = EncryptUtil.decrypt(PropertiesUtil.get("connection.url"));
String name = EncryptUtil.decrypt(PropertiesUtil.get("connection.username"));
String password = EncryptUtil.decrypt(PropertiesUtil.get("connection.password"));
...
}
在安全性要求较高的系统中,不应使用被业界公认的不安全的哈希算法(如MD2、MD4、MD5、SHA、SHA1等)来保证数据的完整性。
例如:下面代码片段中,采用MD5算法来保证数据的完整性。
...
byte[] b = str.getBytes();
MessageDigest md = null;
try {
md = MessageDigest.getInstance("MD5");
md.update(b);
...
}catch (NoSuchAlgorithmException e){
...
}
...
修复建议:
在安全性要求较高的系统中,应采用散列值>=224比特的SHA系列算法(如SHA-224、SHA-256、SHA-384和SHA-512)来保证敏感数据的完整性。
例如:下面代码片段中,使用SHA-256算法取代MD5算法保证数据完整性。
...
byte[] b = str.getBytes();
MessageDigest md = null;
try {
md = MessageDigest.getInstance("SHA-256");
md.update(b);
...
} catch (NoSuchAlgorithmException e) {
...
当程序中使用硬编码加密密钥时,所有项目开发人员都可以查看该密钥,甚至如果攻击者可以获取到程序class文件,可以通过反编译得到密钥,硬编码加密密钥会大大降低系统安全性。
例如:下列代码使用硬编码加密密钥执行AES加密。
private static String encryptionKey = "dfashsdsdfsdgagascv";
...
byte[] keyBytes = encryptionKey.getBytes();
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
Cipher encryptCipher = Cipher.getInstance("AES");
encryptCipher.init(Cipher.ENCRYPT_MODE, key);
...
修复建议:
程序应采用不小于8个字节的随机生成的字符串作为密钥。
例如:以下代码使用KeyGenerator来生成密钥。
...
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(128, new SecureRandom(password.getBytes()));
SecretKey secretKey = kgen.generateKey();
byte[] keyBytes = secretKey.getEncoded();
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
Cipher encryptCipher = Cipher.getInstance("AES");
encryptCipher.init(Cipher.ENCRYPT_MODE, key);
...
该软件在通信信道中传输敏感或安全的关键数据,这些数据可以被未经授权的攻击者嗅探泄密。
例如:下面代码片段中,getConnection()
方法中密码使用了通信信道传入的值。
...
password = readerBuffered.readLine();
Connection connection = DriverManager.getConnection("data-url", "root", password);
...
从通信信道中获取的密码有可能已经被嗅探,从而暴露connection
连接密码。
修复建议:
使用安全通信信道来传输敏感信息,或者对需要传输的敏感数据先进行加密。
例如:下面代码片段中,getConnection()
方法中使用的密码为加密后的密码。
...
password = readerBuffered.readLine();
Connection connection = DriverManager.getConnection("data-url", "root", EncryptUtils.encrypt(password));
...
程序运行时动态解析源代码指令将易于受到攻击。
例如:下面代码片段的作用是计算用户输入的表达式的值。
...
expression = form.expInput.value;
result = eval(expression);
...
如果expression参数是合法的,程序将会正常运行。
例如:当该值为"1 + 1 * 2" 时,result变量被赋予的值将为 3。
如果攻击者提供一个恶意的输入,程序在没有进行合理校验的情况,将可以执行任意代码。
修复建议:
在任何时候,都应尽可能地避免动态的解析源代码。如果程序的功能要求对代码进行动态解析,应用程序不应该直接执行和解析未验证的用户输入。建议创建一份合法操作和数据对象列表,用户可以指定其中的内容,并且只能从中进行选择。
例如:计算表达式的程序可以改为。
...
expression = form.expInput.value;
if(/^[\d\-\+]*$/.test(expression)){
result = eval(expression);
}
...
应用程序的客户端代码从
document.location、request.url、document.URL、document.referrer
或其他任何攻击者可以修改的浏览器对象获取数据,如果未验证数据是否存在恶意代码的情况下,就将其动态更新到页面的DOM节点,应用程序将易于受到基于DOM的XSS攻击。
例如:下面的JavaScript代码片段可从URL中读取msg信息,并将其显示给用户。
var url=document.URL;
document.write(url.substring(url.indexOf("msg=")+4,url.length);
该段脚本解析URL,读取msg参数的值,并将其写入页面。如果攻击者设计一个恶意的URL,并以JavaScript代码作为msg参数,那么Web浏览器就会像显示HTTP响应那样执行该代码,应用程序将受到基于DOM的XSS攻击。
修复建议:
基于DOM的XSS是将用户可控的JavaScript数据输出到HTML页面中而产生的漏洞,为了避免基于DOM的XSS攻击,避免将用户控制的数据直接输出到DOM或脚本中执行。如果不能避免,则应进行严格的过滤。
应用程序允许未验证的用户输入控制重定向中的URL,可能会导致攻击者发动钓鱼攻击。
例1:以下JavaScript代码从用户输入表单的dest参数中读取目的URL,然后在新窗口中打开。
dsturl = myForm.dsturl.value;
window.open(dsturl,"newwin");
假如攻击者可以控制这个表单,那么用户就有可能打开一个恶意站点。
例2:以下是Node.js可能出现的。
var express = require('express');
var app = express();
app.get('/', function (req, res) {
res.redirect(req.url);
});
与例1一样假如攻击者控制了这个url,那么就会导致用户可能打开恶意站点。
修复建议:
js和Node.js都要避免采用不可信数据源的数据来构造重定向的URL,如果业务逻辑需要涉及到用户输入,那么就创建一份合法URL列表,用户只能从中进行选择,进行重定向操作。
例如:以下代码中,用户只能输入数字来选择URL。
dst = myForm.dst.value;
if(dst == "1"){
dsturl = "http://www.1.com"
}else if(dst == "2"){
dsturl = "http://www.2.com"
}else{
dsturl = "http://www.3.com"
}
window.open(dsturl,"newwin");
程序中采用硬编码方式处理密码,一方面会降低系统安全性,一方面不易于维护。
例如:
var password = "123456"
修复建议:
程序中所需密码应从配置文件中获取经过加密的密码值。
在安全性要求较高的系统中,不应使用被业界公认的不安全的哈希算法(如MD5、SHA-1等)来保证数据的完整性。
**例:**以下代码使用MD5的哈希算法加密。
md5("123456");
修复建议:
在安全性要求较高的系统中,应采用散列值>=224比特的SHA系列算法(如SHA-224、SHA-256、SHA-384和SHA-512)来保证敏感数据的完整性。
请勿对加密密钥进行硬编码,因为这样所有项目开发人员都能查看该加密密钥,而且还会大大增加解决问题的难度。一旦代码被使用,除非对软件进行修补,否则加密密钥将再也不能更改。如果受加密密钥保护的帐户遭受入侵,系统所有者将被迫在安全性和可用性之间做出选择。
任何可访问该代码的人都能访问加密密钥。一旦应用程序发布,除非对程序进行修补,否则将无法更改加密密钥。雇员可以利用手中掌握的信息访问权限入侵系统。更糟糕的是,如果攻击者可以访问应用程序的可执行文件,就可以提取加密密钥值。
例如:下面代码的加密密钥设置为硬编码。
var crypto = require('crypto');
var algorithm = 'aes-256-ctr';
var cipher = crypto.createCipher(algorithm, "aaaaa");
修复建议:
避免对加密密钥进行硬编码。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。