使用Struts1的ActionForm是安全敏感的。
All ActionForm's properties should be validated, including their size. Whenever possible, filter the parameters with a whitelist of valid values. Otherwise, escape any sensitive character and constrain the values as much as possible。
可能漏洞:
1).some parameters of the ActionForm might not have been validated properly.
ActionForm传递的参数未经校验就使用。
2).dangerous parameter names are accepted. Example: accept a "class" parameter and use the form to populate JavaBean properties .
接受危险的参数名称。 示例:接受“class”类型参数并使用该表单填充JavaBean属性。
3).there are unused fields which are not empty or undefined.
不要在ActionForm中添加未使用的字段。
安全编码:
ActionForm:
ActionForm类是Struts框架的核心组件之一,是Struts的关键视图组件。ActionForm的作用机理:
ActionForm本质上是一种JavaBean,是专门用来传递表单数据的DTD(Data Transfer Object,数据传递对象)。它包括用于表单数据验证的validate()方法和用于数据复位的reset()方法 。
// Struts 1.1+
public final class CashTransferAction extends Action {
public String fromAccount = "";
public String toAccount = "";
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest req, HttpServletResponse res) throws Exception {
// usage of the "form" object to call some services doing JDBC actions
[...]
return mapping.findForward(resultat);
}
}
参考:
https://www.aliyun.com/jiaocheng/321042.html
https://blog.csdn.net/huihui870311/article/details/51023050
在Struts 2中使用setter ActionSupport是安全敏感的
All classes extending com.opensymphony.xwork2.ActionSupport are potentially remotely reachable. An action class extending ActionSupport will receive all HTTP parameters sent and these parameters will be automatically mapped to the setters of the Struts 2 action class. One should review the use of the fields set by the setters, to be sure they are used safely. By default, they should be considered as untrusted inputs.
所有继承ActionSupport的类都可以被远程访问的,通过HTTP发送过来的参数会自动匹配setters方法对应的属性。需要校验使用setter字段设置的字段,确保被安全使用。
可能漏洞:
如果不是一个映射查询参数,不需要设置setter属性时候设置了setter。
2.the value provided to the setter is properly sanitized before being used or stored.
前端传入的参数未经校验就使用了。
安全编码:
public class AccountBalanceAction extends ActionSupport {
private static final long serialVersionUID = 1L;
private Integer accountId;
// this setter might be called with user input
public void setAccountId(Integer accountId) {
this.accountId = accountId;
}
@Override
public String execute() throws Exception {
// call a service to get the account's details and its balance
[...]
return SUCCESS;
}
}
Attackers might be able to decompile the code and thereby discover a potentially sensitive address. They can perform a Denial of Service attack on the service at this address or spoof the IP address. Such an attack is always possible, but in the case of a hardcoded IP address the fix will be much slower, which will increase an attack's impact.
硬编码IP是不安全的,攻击者可以反编译代码获取IP,可以对此地址的服务执行拒绝服务攻击或欺骗IP地址。并且在硬编码的情况下,修复会慢很多。
String ip = "192.168.12.42"; // Noncompliant
Socket socket = new Socket(ip, 6667);
改进:将 IP放入配置文件中。
The "secure" attribute prevents cookies from being sent over plaintext connections such as HTTP, where they would be easily eavesdropped upon. Instead, cookies with the secure attribute are only sent over encrypted HTTPS connections。
带有secure属性的cookies只能通过加密的HTTPS连接发送,可以防止通过纯文本的HTTP连接发送数据。HTTP连接数据容易被窃取。
HTTP与HTTPS区别:
HTTP协议传输的数据都是未加密的,也就是明文的,因此使用HTTP协议传输隐私信息非常不安全,为了保证这些隐私数据能加密传输,于是网景公司设计了SSL(Secure Sockets Layer)协议用于对HTTP协议传输的数据进行加密,从而就诞生了HTTPS。简单来说,HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全。
Cookie c = new Cookie(SECRET, secret); // Noncompliant; cookie is not secure
response.addCookie(c);
改进:
Cookie c = new Cookie(SECRET, secret);
c.setSecure(true);
response.addCookie(c);
PRNG是通过某一种确定性算法来生成随机数。它们并不是真正的随机数,而是看起来是随机的。即可以通过我们所能找到的所有随机性统计检验。由于这些数字有可重复性,所以它们是伪随机的。
As the java.util.Random class relies on a pseudorandom number generator, this class and relating java.lang.Math.random() method should not be used for security-critical applications or for protecting sensitive data. In such context, the java.security.SecureRandom class which relies on a cryptographically strong random number generator (RNG) should be used in place.
由于java.util.Random类依赖于伪随机数生成器,因此该类和相关的java.lang.Math.random()方法不应用于安全关键应用程序或保护敏感数据。 在这种情况下,应该使用依赖于加密强随机数生成器(RNG)的java.security.SecureRandom类。
PRNG(伪随机数):
伪随机数, 计算机不能生成真正的随机数,而是通用一定的方法来模拟随机数。伪随机数有一部分遵守一定的规律,另一部分不遵守任何规律。
RNG(随机数):
随机数是由“随机种子”产生的,“随机种子”是一个无符号整形数。
反例:
Random random = new Random(); // Questionable use of Random
byte bytes[] = new byte[20];
random.nextBytes(bytes);
正例:
SecureRandom random = new SecureRandom();
byte bytes[] = new byte[20];
random.nextBytes(bytes);
参考:
http://blog.51cto.com/mzhang/1276644
http://www.what21.com/sys/view/java_java-secure_1473229611366.html
private methods were made private for a reason, and the same is true of every other visibility level. Altering or bypassing the accessibility of classes, methods, or fields violates the encapsulation principle and could introduce security holes.
更改或绕过一个类的私有方法或属性,违反了封装原则,可能引发安全漏洞。
This rule raises an issue when reflection is used to change the visibility of a class, method or field, and when it is used to directly update a field value.
当通过反射修改一个类的私有属性时,可能会引发安全问题。
使用ClassLoaders和SecurityManagers来沙箱化任何不受信任的代码并禁止访问Reflection API。
安全编码:
1.使用加密强大的随机数生成器(RNG) 如“java.security.SecureRandom”代替此PRNG。
2.仅使用生成的随机值一次。
3.您不应该公开生成的随机值。 如果必须存储它,请确保数据库或文件是安全的。
public void makeItPublic(String methodName) throws NoSuchMethodException {
this.getClass().getMethod(methodName).setAccessible(true); // Questionable
}
public void setItAnyway(String fieldName, int value) {
this.getClass().getDeclaredField(fieldName).setInt(this, value); // Questionable; bypasses controls in setter
}
生产环境代码启动debug模式是安全敏感的。
An application's debug features enable developers to find bugs more easily. It often gives access to detailed information on both the system running the application and users. Sometime it even enables the execution of custom commands. Thus deploying on production servers an application which has debug features activated is extremely dangerous.
应用的debug模式可以让开发人员轻松找到bugs。但它也可以查看用户的详细信息,甚至可以执行自定义命令。
安全编码:
1.生产环境代码禁止启用debug模式。
反例:
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
@Configuration
@EnableWebSecurity(debug = true) // Noncompliant
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
// ...
}
正例:
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
@Configuration
@EnableWebSecurity(debug = false) // Compliant
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
// ...
}
哈希数据是安全敏感的。
Cryptographic hash functions are used to uniquely identify information without storing their original form. When not done properly, an attacker can steal the original information by guessing it (ex: with a rainbow table), or replace the original data with another one having the same hash。
加密散列函数用于唯一地标识信息而不存储其原始数据。操作不当攻击者会通过猜测(彩虹表)窃取其原始数据,或者替换原始数据。
漏洞编码:
1.the hashed value is used in a security context.
将散列值用于安全上下文的凭证。
2.the hashing algorithm you are using is known to have vulnerabilities.
使用的哈希算法已知具有漏洞。
3.salts are not automatically generated and applied by the hashing function.
盐不是通过hashing的方法来自动生成。
4.any generated salts are cryptographically weak or not credential-specific.
生成的盐是弱加密或者不是凭证特定的。
安全编码:
1.使用安全哈希算法。避免在安全上下文中完全使用MD5和SHA1等算法。
2.禁止自定义哈希算法或盐算法,因为可能是有缺陷的。
3.不使用计算太快的算法如SHA256,因为它必须超越现代硬件功能来执行暴力破解和基于字典的攻击。
4.将salt和哈希值保存在相关的数据库记录中。在将来的验证操作中,可以从数据库中检索salt和hash。
反例:
import com.google.common.hash.Hashing;
void foo() {
Hashing.md5(); // Questionable
Hashing.sha1(); // Questionable
Hashing.sha256(); // Questionable
Hashing.sha384(); // Questionable
Hashing.sha512(); // Questionable
}
注:使用Hashing(import com.google.common.hash.Hashing)的mad5()方法或者sha*()方法会引发安全问题。
反例:
// === MessageDigest ===
import java.security.MessageDigest;
import java.security.Provider;
class A {
void foo(String algorithm, String providerStr, Provider provider) throws Exception {
MessageDigest.getInstance(algorithm); // Questionable
MessageDigest.getInstance(algorithm, providerStr); // Questionable
MessageDigest.getInstance(algorithm, provider); // Questionable
}
注:关于SecretKeyFactory。 将优先使用以“PBKDF2”开头的参数调用SecretKeyFactory.getInstance(“...”)。 请参阅OWASP指南,android上的标准算法和算法列表。
参考:http://www.owasp.org.cn/owasp-project/secure-coding
日志文件的配置是安全敏感的
漏洞编码:
1.Logs are also a target for attackers because they might contain sensitive information. Configuring loggers has an impact on the type of information logged and how they are logged.
日志文件也是攻击者的目标,因为它们可能包含敏感信息。日志文件的配置会影响记录的信息类型以及记录方式。
2.the logs contain sensitive information on a production server. This can happen when the logger is in debug mode.
当日志级别为debug时,有可能会把生产服务器上有一些敏感的数据暴露出来。
安全编码:
反例:
// === Logback ===
import ch.qos.logback.classic.util.ContextInitializer;
import ch.qos.logback.core.Appender;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.*;
class M {
void foo(Logger logger, Appender fileAppender) {
System.setProperty(ContextInitializer.CONFIG_FILE_PROPERTY, "config.xml"); // Questionable
JoranConfigurator configurator = new JoranConfigurator(); // Questionable
logger.addAppender(fileAppender); // Questionable
logger.setLevel(Level.DEBUG); // Questionable
}
}
Socket的使用是安全敏感的
漏洞编码:
1.sockets are created without any limit every time a user performs an action.
用户毫无限制的创建Socket连接。
2.input received from sockets is used without being sanitized.
在使用socket接受的数据时没有对数据检查。
3.sensitive data is sent via sockets without being encrypted.
使用socket发送未加密的敏感数据
安全编码:
反例:
// === java.net ===
import java.net.Socket;
import java.net.InetAddress;
import java.net.Proxy;
import java.net.ServerSocket;
import javax.net.SocketFactory;
class A {
void foo(SocketFactory factory, String address, int port, InetAddress localAddr, int localPort, boolean stream,
String host, Proxy proxy, int backlog, InetAddress bindAddr)
throws Exception {
new Socket(); // Questionable.
new Socket(address, port); // Questionable.
new Socket(address, port, localAddr, localPort); // Questionable.
new Socket(host, port, stream); // Questionable.
new Socket(proxy); // Questionable.
new Socket(host, port); // Questionable.
new Socket(host, port, stream); // Questionable.
new Socket(host, port, localAddr, localPort); // Questionable.
new ServerSocket(); // Questionable.
new ServerSocket(port); // Questionable.
new ServerSocket(port, backlog); // Questionable.
new ServerSocket(port, backlog, bindAddr); // Questionable.
factory.createSocket(); // Questionable
}
}
abstract class mySocketFactory extends SocketFactory { // Questionable. Review how the sockets are created.
// ...
}
参考:https://blog.csdn.net/lucyxu107/article/details/74530966
文件处理是安全敏感的
Any access to the file system can create a vulnerability. Exposing a file's content, path or even its existence or absence is dangerous. It is also extremely risky to create or write files without making sure that their permission and content is safe and controlled. Using a file path or reading a file content must be always done with caution as they could have been tampered with.
文件系统的任何访问都可能产生漏洞。保证文件路径位置的安全。
The file system is a resource which can be easily exhausted. Opening too many files will use up all file descriptors, preventing other software from opening files. Filling the storage space will also prevent any additional write from happening.
读写文件是很消耗系统资源的。防止恶意软件频繁读取文件,导致系统崩溃。
漏洞编码:
1.the file or directory path you are using is coming from a user input or could have been tampered with.
使用的文件路径来自于用户输入。
2."Unauthorized" error when the file/directory exists but the person can't perform an action.
可能使用错误的权限创建文件或目录。
3.the code exposes to an unauthorized person the paths of files and/or directories, for example by listing the content of a directory and displaying the output.
代码向未经授权的人公开文件和/或目录的路径,例如通过列出目录的内容并显示输出。
4.a file is read and its content is used without being validated.
读写文件并使用其内容而不进行验证。
安全编码:
// === org.apache.commons.io.FileUtils ===
import org.apache.commons.io.FileUtils;
class A {
void foo() {
FileUtils.getFile("test.txt"); // Questionable
FileUtils.getTempDirectory(); // Questionable
FileUtils.getUserDirectory(); // Questionable
}
}
// === java.io.File ===
import java.io.File;
class A {
void foo(String strPath, String StrParent, String StrChild, String prefix, String suffix, java.net.URI uri) throws Exception {
// Questionable: check what is done with this file
new File(strPath);
new File(StrParent, StrChild);
new File(uri);
File.createTempFile(prefix, suffix);
}
}
执行sql查询是安全敏感的,如果查询语句书写不当会造成SQL注入
SQL injection is still one of the top 10 security vulnerabilities. Applications that execute SQL commands should neutralize any externally-provided values used in those commands. Failure to do so could allow an attacker to include input that changes the query so that unintended commands are executed, or sensitive data is exposed. Instead of trying to sanitize data by hand, SQL binding mechanisms should be used; they can be relied on to automatically perform a full sanitization.
SQL注入仍然是十大安全漏洞之一。 执行SQL命令的应用程序应该拒绝任何外部提供的SQL命令。 如果不这样做,攻击者可能会改变更改查询条件,以便执行非预期的命令,或者暴露敏感数据。
安全编码:
1.避免使用拼接Sql语句查询。
2.使用PreparedStatement预编译语句集处理sql,它内置了处理SQL注入的能力。
3.使用Hibernate、mybatis等ORM框架,如果使用正确,可以降低注入风险。
4.使用低权限的数据库账户来减少攻击。
反例:
public User getUser(Connection con, String user) throws SQLException {
Statement stmt1 = null;
Statement stmt2 = null;
PreparedStatement pstmt;
try {
stmt1 = con.createStatement();
ResultSet rs1 = stmt1.executeQuery("GETDATE()"); // Compliant; parameters not used here
stmt2 = con.createStatement();
ResultSet rs2 = stmt2.executeQuery("select FNAME, LNAME, SSN " +
"from USERS where UNAME=" + user); // Noncompliant; parameter concatenated directly into query
pstmt = con.prepareStatement("select FNAME, LNAME, SSN " +
"from USERS where UNAME=" + user); // Noncompliant; parameter concatenated directly into query
ResultSet rs3 = pstmt.executeQuery();
//...
}
public User getUserHibernate(org.hibernate.Session session, String userInput) {
org.hibernate.Query query = session.createQuery( // Compliant
"FROM students where fname = " + userInput); // Noncompliant; parameter binding should be used instead
// ...
}
正例:
public User getUser(Connection con, String user) throws SQLException {
Statement stmt1 = null;
PreparedStatement pstmt = null;
String query = "select FNAME, LNAME, SSN " +
"from USERS where UNAME=?"
try {
stmt1 = con.createStatement();
ResultSet rs1 = stmt1.executeQuery("GETDATE()");
pstmt = con.prepareStatement(query);
pstmt.setString(1, user); // Compliant; PreparedStatements escape their inputs.
ResultSet rs2 = pstmt.executeQuery();
//...
}
}
public User getUserHibernate(org.hibernate.Session session, String userInput) {
org.hibernate.Query query = session.createQuery("FROM students where fname = ?");
query = query.setParameter(0,userInput); // Parameter binding escapes all input
// ...
参考:https://www.cnblogs.com/baizhanshi/p/6002898.html