代码漏洞说明

2023-11-03

1. 代码注入:命令注入

命令注入是指,在应用程序执行的命令中包含来源于不可信数据时,程序本身没有对这些不可信数据做正确、合理的验证和过滤,导致系统执行恶意命令。
例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. 程序对非受信的用户输入数据进行净化,删除不安全的字符。
  2. 创建一份安全字符串列表,限制用户只能输入该列表中的数据。
  3. 配置URL访问控制策略:部署于公网的axis服务器,可通过ACL禁止对/services/AdminService及/services/FreeMarkerService路径的访问。
  4. 禁用axis远程管理功能:axis<=1.4版本默认关闭了远程管理功能,如非必要请勿开启。若需关闭,则需修改axis目录下WEB-INF文件夹中的server-config.wsdd文件,将其中"enableRemoteAdmin"的值设置为false。

例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
}
...

2. 代码注入:HTTP响应截断

程序从一个不可信赖的数据源获取数据,未进行验证就置于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);
}
...

3. 代码注入:有风险的SQL查询:MyBatis

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注入的方法如下:

  1. 正确使用参数化API进行SQL查询。
  2. 如果构造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>

4. 代码注入:SQL注入

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
        }
    }
}

在上面的例子中,攻击者能够自由控制输入的字符串变量usernamepassword中的内容,他们可以使用下面的关于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注入攻击。
  3. 避免出现一些详细的错误消息,防止攻击者利用报错信息来判断后台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
        }
    }
}

5. 代码注入:SQL注入:MyBatis

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注入的方法如下:

  1. 正确使用参数化API进行SQL查询。
  2. 如果构造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>

6. 代码注入:有风险的SQL查询

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
        }
    }
}

如果攻击者能够替代usernamepassword中的任意字符串,它们可以使用下面的关于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'

修复建议

常见的修复方法:

  1. 使用预编译处理输入参数:要防御SQL注入,用户的输入就不能直接嵌套在SQL语句中。使用参数化的语句,用户的输入就被限制与一个参数当中。
  2. 输入验证:检查用户输入的合法性,以确保输入内容是正规数据。在客户端和服务器端都要进行数据检查,之所以要执行服务器端验证,是因为客户端的校验往往只是减轻服务器的压力和提高对用户的友好度,攻击者完全有可能通过抓包修改参数或者是获得网页的源代码后,修改验证合法性的脚本(或直接删除),然后将非法内容通过修改后的表单提交给服务器等手段绕过客户端的校验。因此,要保验证处理,唯一的办法就是在服务端也做验证。但是这些方法很容易出现由于过滤不严,导致恶意攻击者可能绕过这些过滤的情况发生,所以需要慎重使用。
  3. 错误消息处理:防范SQL注入,还要避免出现一些详细的错误信息,攻击者往往会利用给这些报错信息来判断后台SQL的拼接方式,甚至是直接利用给这些报错,将数据库中的数据通过报错信息显示出来。
  4. 加密处理:将用户登录名称、密码等数据加密保存。加密用户输入的数据,然后再将它与数据库中保存的数据比较,这相当与对用户输入的数据进行了“消毒”处理,用户输入的数据不再对数据库有任何特殊的意义,从而也就防止了攻击者注入SQL命令。
    例如:以下代码片段使用java.sql.PreparedStatement代替java.sql.Statementjava.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
        }
    }
}

7. 跨站脚本:存储型XSS

存储型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");
...

8 跨站脚本:反射型XSS

反射型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");
...

9. 输入验证:重定向

应用程序允许未验证的用户输入控制重定向中的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);
            }
        ...
        }
    }
}

10 输入验证:路径遍历

应用程序对用户可控制的输入未经合理校验,就传送给一个文件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文件的父目录。

修复建议:

预防路径遍历的威胁,有以下三种方法:

  1. 程序对非受信的用户输入做过滤和验证,对网站用户提交的文件路径进行硬编码或统一编码,过滤非法字符。
  2. 对文件后缀进行白名单控制,拒绝包含了恶意的符号或空字节。
  3. 合理配置Web服务器的目录访问权限。

11. 密码管理:不安全的随机数

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) {
    ...
    }
}

12. 密码管理:硬编码密码

程序中采用硬编码方式处理密码,一方面会降低系统安全性,另一方面不易于程序维护。
例如:下列代码中采用硬编码方式处理密码。

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"));
...
}

13. 密码管理:不安全的哈希算法

在安全性要求较高的系统中,不应使用被业界公认的不安全的哈希算法(如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) {
...

14. 密码管理:硬编码加密密钥

当程序中使用硬编码加密密钥时,所有项目开发人员都可以查看该密钥,甚至如果攻击者可以获取到程序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);
...

15. 代码质量:敏感信息泄露

该软件在通信信道中传输敏感或安全的关键数据,这些数据可以被未经授权的攻击者嗅探泄密。
例如:下面代码片段中,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));
...

16. 代码注入:动态解析代码

程序运行时动态解析源代码指令将易于受到攻击。
例如:下面代码片段的作用是计算用户输入的表达式的值。

...
expression = form.expInput.value;
result = eval(expression);
...

如果expression参数是合法的,程序将会正常运行。
例如:当该值为"1 + 1 * 2" 时,result变量被赋予的值将为 3。
如果攻击者提供一个恶意的输入,程序在没有进行合理校验的情况,将可以执行任意代码。
修复建议:
在任何时候,都应尽可能地避免动态的解析源代码。如果程序的功能要求对代码进行动态解析,应用程序不应该直接执行和解析未验证的用户输入。建议创建一份合法操作和数据对象列表,用户可以指定其中的内容,并且只能从中进行选择。
例如:计算表达式的程序可以改为。

...
expression = form.expInput.value;
if(/^[\d\-\+]*$/.test(expression)){
result = eval(expression);
}
...

17. 跨站脚本:基于DOM的XSS

应用程序的客户端代码从

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或脚本中执行。如果不能避免,则应进行严格的过滤。

18. 输入验证:重定向

应用程序允许未验证的用户输入控制重定向中的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");

19. 密码管理:硬编码密码

程序中采用硬编码方式处理密码,一方面会降低系统安全性,一方面不易于维护。
例如

var password = "123456"

修复建议:
程序中所需密码应从配置文件中获取经过加密的密码值。

20. 密码管理:不安全的哈希算法

在安全性要求较高的系统中,不应使用被业界公认的不安全的哈希算法(如MD5、SHA-1等)来保证数据的完整性。
**例:**以下代码使用MD5的哈希算法加密。

md5("123456");

修复建议:
在安全性要求较高的系统中,应采用散列值>=224比特的SHA系列算法(如SHA-224、SHA-256、SHA-384和SHA-512)来保证敏感数据的完整性。

21 密码管理:硬编码加密密钥

请勿对加密密钥进行硬编码,因为这样所有项目开发人员都能查看该加密密钥,而且还会大大增加解决问题的难度。一旦代码被使用,除非对软件进行修补,否则加密密钥将再也不能更改。如果受加密密钥保护的帐户遭受入侵,系统所有者将被迫在安全性和可用性之间做出选择。
任何可访问该代码的人都能访问加密密钥。一旦应用程序发布,除非对程序进行修补,否则将无法更改加密密钥。雇员可以利用手中掌握的信息访问权限入侵系统。更糟糕的是,如果攻击者可以访问应用程序的可执行文件,就可以提取加密密钥值。
例如:下面代码的加密密钥设置为硬编码。

var crypto = require('crypto');
var algorithm = 'aes-256-ctr';
var cipher = crypto.createCipher(algorithm, "aaaaa");

修复建议:
避免对加密密钥进行硬编码。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

代码漏洞说明 的相关文章

  • 如何使用 Apache POI API 将图像添加到 pptx 中添加的图像占位符?

    我已经预定义了带有文本和图像占位符的 pptx 模板 我如何从模板访问和修改这些占位符 我可以使用 POI pptx API 直接将图像和文本添加到幻灯片中 但如何将其添加到模板的占位符中 请参阅链接以了解如何添加占位符来创建固定模板 ht
  • Java中字符串中特殊字符的替换

    Java中如何替换字符串 E g String a adf sdf 如何替换和避免特殊字符 您可以删除除此之外的所有字符可打印的 ASCII 范围 http en wikipedia org wiki ASCII ASCII printab
  • Eclipse 在源代码管理中保存操作

    我们希望找到一种在签入之前执行代码标准的 轻量级 方法 我们真的很喜欢使用 Eclipse 内置的想法保存操作 go to Preferences gt gt Java gt gt Editor gt gt Save Actions 其中有
  • 在文本文件中写入多行(java)

    下面的代码是运行命令cmd并使用命令行的输出生成一个文本文件 下面的代码在 Eclipse 的输出窗口中显示了正确的信息 但在文本文件中只打印了最后一行 谁能帮我这个 import java io public class TextFile
  • OSGi:如果不取消服务会发生什么

    这是我获取 OSGi 服务的方式 ServiceReference reference bundleContext getServiceReference Foo class getName Foo foo Foo bundleContex
  • 我可以使用子接口重新编译公共 API 并保持二进制兼容性吗?

    我有一个公共 API 在多个项目中多次使用 public interface Process
  • 具有 java XSLT 扩展的数组

    我正在尝试使用 java 在 XSLT 扩展中使用数组 我收到以下错误 Caused by java lang ClassCastException org apache xpath objects XObject cannot be ca
  • 使用 SQLITE 按最近的纬度和经度坐标排序

    我必须获得一个 SQLite SQL 语句 以便在给定初始位置的情况下按最近的纬度和经度坐标进行排序 这是我在 sqlite 数据库中的表的例句 SELECT id name lat lng FROM items EXAMPLE RESUL
  • 普罗米修斯指标 - 未找到

    我有 Spring Boot 应用程序 并且正在使用 vertx 我想监控服务和 jvm 为此我选择了 Prometheus 这是我的监控配置类 Configuration public class MonitoringConfig Bea
  • 以编程方式在java的resources/source文件夹中创建文件?

    我有两个资源文件夹 src 这是我的 java 文件 资源 这是我的资源文件 图像 properties 组织在文件夹 包 中 有没有办法以编程方式在该资源文件夹中添加另一个 properties 文件 我尝试过这样的事情 public s
  • 在游戏视图下添加 admob

    我一直试图将 admob 放在我的游戏视图下 这是我的代码 public class HoodStarGame extends AndroidApplication Override public void onCreate Bundle
  • IntelliJ - 调试模式 - 在程序内存中搜索文本

    我正在与无证的第三方库合作 我知道有一定的String存储在库深处的某个字段中的某处 我可以预测的动态值 但我想从库的 API 中获取它 有没有一种方法可以通过以下方式进行搜索 类似于全文搜索 full程序内存处于调试模式并在某个断点处停止
  • 如何知道抛出了哪个异常

    我正在对我们的代码库进行审查 有很多这样的陈述 try doSomething catch Exception e 但我想要一种方法来知道 doSomething 抛出了哪个异常 在 doSomething 的实现中没有 throw 语句
  • 如何在JSTL中调​​用java方法? [复制]

    这个问题在这里已经有答案了 这可能是重复的问题 我只想调用不是 getter 或 setter 方法的方法例如 xyz 类的 makeCall someObj stringvalue Java类 Class XYZ public Strin
  • Java中的Object类是什么?

    什么是或什么类型private Object obj Object http download oracle com javase 6 docs api java lang Object html是Java继承层次结构中每个类的最终祖先 从
  • 为什么这个作业不起作用?

    我有课Results which extends ArrayList
  • FileOutputStream.close() 中的设备 ioctl 不合适

    我有一些代码可以使用以下命令将一些首选项保存到文件中FileOutputStream 这是我已经写了一千遍的标准代码 FileOutputStream out new FileOutputStream file try BufferedOu
  • Trie 数据结构 - Java [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 是否有任何库或文档 链接提供了在 java 中实现 Trie 数据结构的更多信息 任何帮助都会很棒 Thanks 你可以阅读Java特里树
  • 在 RESTful Web 服务中实现注销

    我正在开发一个需要注销服务的移动应用程序 登录服务是通过数据库验证来完成的 现在我陷入了注销状态 退一步 您没有提供有关如何在应用程序中执行身份验证的详细信息 并且很难猜测您在做什么 但是 需要注意的是 在 REST 应用程序中 不能有会话
  • GUI Java 程序 - 绘图程序

    我一直试图找出我的代码有什么问题 这个想法是创建一个小的 Paint 程序并具有红色 绿色 蓝色和透明按钮 我拥有我能想到的让它工作的一切 但无法弄清楚代码有什么问题 该程序打开 然后立即关闭 import java awt import

随机推荐

  • 如何评估大型语言模型(LLM)?

    编者按 近期几乎每隔一段时间 就有新的大语言模型发布 但是当下仍然没有一个通用的标准来评估这些大型语言模型的质量 我们急需一个可靠的 综合的LLM评估框架 本文说明了为什么我们需要一个全面的大模型评估框架 并介绍了市面上这些现有的评估框架
  • 地址解析协议 (ARP)

    地址解析协议 ARP 是互联网协议 IP 套件的关键第 2 层协议 可将 IP 地址转换为媒体访问控制 MAC 地址 IP MAC ARP 在实现网络连接方面发挥着不可或缺的作用 能够发现本地网络上设备的硬件地址并将其映射到其 IP 地址
  • STM32F429 不断重复复位

    之前做过一块STM32F429的板子 板子搭载SDRAM和NAND flash 刚开始板子还是好好的 用了一段时间之后 板子变得很奇怪 开机后SDRAM和NAND初始化之后 运行SDRAM的测试代码 大概运行10S左右就会出现一次复位 我在
  • html设置一段文字颜色,用span css设置div内部分字体颜色

    用span标签设置div内放一段文字中的一小部分文字字体色采方式 一段笔墨放在DIV内或P内 当咱们配置div或p设置字体色彩 内里全体笔墨的字体色调就会变成咱们所配置字体色彩 通常会结构一段翰墨中个中几个字或一小块字的字体色采不同 此时就
  • Hibernate学习(2)- hibernate.cfg.xml详解

    1 主配置文件主要分为三部分 注意 通常情况下 一个session factory节点代表一个数据库 1 1 第一部分 数据库连接部分 注意 hibernate connection driver class 中间的 1 2 第二部分 其他
  • LintCode 202. Segment Tree Query (线段树经典题!)

    Segment Tree Query 中文English For an integer array index from 0 to n 1 where n is the size of this array in the correspon
  • 玩转ChatGPT:视频制作

    一 写在前面 最近 在码深度学习图像识别的相关知识和代码 这一part 看看能否用小Chat搞一个介绍视频 简单问小Chat 咒语 我怎么使用你做一个视频 需要配合什么软件生成 大意就是 惊呆了 这不是我想要的 还是先半自动 后全自动吧 二
  • flink启动报错Failed to construct kafka producer

    flink local模式下启动 sink2kafka报错 具体报错如下 apache kafka common KafkaException Failed to construct kafka producer at org apache
  • python谁是卧底、猜词语

    python谁是卧底 谁是卧底也是深受很多人喜欢的游戏 起码要三人以上才能玩 大致分为几个阶段 1 分配平民词语和卧底词语 gt 2 玩家依次发言 gt 3 根据发言投票认为谁是卧底 gt 4 得到票数最多的玩家出局 gt 5 出局玩家刚好
  • 网络安全—攻防

    招聘需求 尝试通过收集招聘平台的相关职业岗位描述DJ 进行相关方面能力学习 攻防安全 认证 TCSP证书 CISM证书 CISP证书 CISSP证书 CISP PTE证书 CISP DSG证书 CISP A证书 CISD证书 CCSRP证书
  • 2020-10-14 KIBANA7 配置(搜索、可视化组件和仪表板)导出导入

    需求描述 线上Kibana的可视化图表跟仪表盘配置意外丢失了 还好测试环境有相同的配置 根据Kibana的功能进行配置的导出 gt 导入 避免手工一个一个重新配置的繁琐跟配置错误疏漏等情况 也同时进行下配置文件的导出备份工作 参考资料 官方
  • 好分数阅卷3.0_自考阅卷老师是怎么打分的?

    距离十月自考还有一个月 又到了全国考生转发考神的时间 但还有一招更有用 解密阅卷老师 往年很多同学查分后 都会有这么几个疑问 在答题的时候 感觉每道题都答得不错 为什么分数只有这么点 56 57这种分数 搞不懂老师为什么就不能多给我几分 俗
  • Matlab如何打包成jar并给java使用(混合编程)

    Matlab如何打包成jar并给java使用 由于期末数字图像课程设计需求 使用matlab码好了函数可是没有界面 所以打算用jsp随便搞一搞 可是这样就要跨语言编程了 说得很高大上其实就是打成jar然后丢到项目lib包里面去 这时就需要打
  • H5——连连看小游戏实现思路及源码

    部门要求推广新产品用连连看小游戏的方式 设计那边UI还没有排期 先撸个功能demo 正好记录一下 连连看都玩过 程序的关键在于判断连续点击的两张图片是否能够消除 两个图片消除的条件有两个 图片相同 两张图之间连线的转角数不超过2 第一个条件
  • 高级纹理映射技术(6)

    高级纹理映射技术 6 对一些特殊的应用需要对纹理坐标进行处理 主要包括纹理坐标自动生成和纹理坐标变换 下图显示了纹理坐标的来源 处理过程以及到达光栅处理器的过程 纹理坐标自动生成 在Direct3D程序中 不仅可以在模型载入阶段或渲染阶段指
  • EPICS asynPortDriver中数组用法示例

    本驱动程序是继承自asynPortDriver 分别重写了用于读取32位整型数组和32位浮点型数组的 readInt32Array和readFloat32Array 1 源代码如下 arraydriver h include epicsEv
  • 30道软件测试高频面试题

    如果哪个测试经理在看我的文章 希望对面试者要微笑 不然面试结束 出门之后就一万个草泥马奔腾而过 其实面试者并不是希望你给他们什么 而是一种尊重 平等的谈话 不要高高在上感觉自己超牛逼一样 任何大牛都是从菜鸟起步的 当然 正在学习测试技术的人
  • VUE之Vxe-table动态生成多级表头

    需求 1 第一列为正常列 2 第二列开始为动态生成列 根据接口返回数据生成 3 最后一列为编辑列 实现步骤 模板中定义
  • Java 类的主动使用和被动使用

    Java程序对类的使用方式分为 主动使用和被动使用 主动使用 又分为七种情况 1 创建类的实例 2 访问某个类或者接口的静态变量 或者对该静态变量赋值 3 反射 比如 Class forName java lang String 4 初始化
  • 代码漏洞说明

    1 代码注入 命令注入 命令注入是指 在应用程序执行的命令中包含来源于不可信数据时 程序本身没有对这些不可信数据做正确 合理的验证和过滤 导致系统执行恶意命令 例1 以下代码通过Runtime exec 方法调用Windows的dir命令