导读:如今软件的安全性比以往任何时间都要重要。本文为各位提供了多个编码最佳实践,各位在编码时可以有效利用。

 

 

背景

 

在当今世界,软件的安全性比以往任何时候都重要。如果我们将安全实时嵌入到应用程序的开发中,不仅有利于应用程序的整体安全,还可以在软件级别上创建多个安全检查点。

 

在本文中,我们会提供多个实时安全编码的例子,这些例子在开发现代软件时必须应用。本文中使用 Java 来展示实例,但这些示例可以用任何一种编程语言编写。

 

1、用户输入转义

 

有几种类型的攻击行为,最严重的是 SQL 注入攻击。这种攻击者在输入文字时混入了数据库查询指令,用来糊弄 SQL 执行引擎,向攻击者提供更多有用的信息,甚至有可能被控制。

 

要避免此类攻击,要在用户输入处理中加入转义,避免解析命令,而将其视为普通文本——经典的方法就是将数据库存储的数据进行转义。

 

在一些场景中,有一些用户在发帖时输入了 JavaScript 脚本,用来取得 Cookie,如果未加文章转义,JavaScript 将被执行,为攻击者提供更多的信息控制。如下代码示例:

 

有风险的代码:

String query = "SELECT user_id FROM user_data WHERE user_name = '"
              + req.getParameter("userID")
              + "' and user_password = '" + req.getParameter("pwd") +"'";
try {
    Statement statement = connection.createStatement( … );
    ResultSet results = statement.executeQuery( query );
}

 

去除风险的代码:

Codec ORACLE_CODEC = new OracleCodec();
String query = "SELECT user_id FROM user_data WHERE user_name = '"
+ ESAPI.encoder().encodeForSQL( ORACLE_CODEC, req.getParameter("userID"))
+ "' and user_password = '"
+ ESAPI.encoder().encodeForSQL( ORACLE_CODEC, req.getParameter("pwd")) +"'";

 

2.避免使用自增长序列

 

在某些情况下,攻击者试图获取比其应有的更多信息。比如,如果API的用户允许查看ID为1-100的用户。现在,如果系统使用自增长 ID序列,那么下一个用户将是101。

 

此攻击者可以利用此漏洞来获取有关用户并不应该获得的信息。

 

代码示例:

 

潜在风险代码

String sqlIdentifier = "select TESTING_SEQ.NEXTVAL from dual";
PreparedStatement pst = conn.prepareStatement(sqlIdentifier);
synchronized( this ) {
   ResultSet rs = pst.executeQuery();
   if(rs.next())
     long myId = rs.getLong(1);

 

去除风险的代码:​​​​​​​

// This example is for Oracle
String sqlIdentifier = "select TESTING_SEQ.NEXTVAL from dual";
PreparedStatement pst = conn.prepareStatement(sqlIdentifier);
synchronized( this ) {
   ResultSet rs = pst.executeQuery();
   if(rs.next())
     long myId = rs.getLong(1) + UUID.random();

 

3、运用极简主义方法

 

为了减少网络攻击行为,系统应该采用最小空间占用的原则——从本质上讲,系统不应该暴露相关的权限。我们来举个例子,如果有一项业务,系统需要使用200 HTTP 编码来响应资源已经存在,比如 REST API 提供了 GET 方法,则会增加攻击者的范围。

 

正确的方法是,系统应该只有 HTTP 协议的 head 方法,该方法只提供相关存在的信息。

 

代码示例:

有风险的代码:​​​​​​​

//Get is allowed where we need to just check user exist
​​​​​​​http://localhost:8080/User/id/1

 

无风险的代码:​​​​​​​

http://localhost:8080/User/id/1
​​​​​​​Head

 

 

4、最低权限原则 

 

假设以某种方法,客户服务部门的一位用户权限被攻击,本来她只以访问订单数据API,但他却被分配了超级管理员的角色。

 

攻击者利用其身份掩护,对系统发起一系列攻击。为了减少攻击维度,应根据角色需要来对 API 授权,不应该有可以访问所有内容的超级用户概念。

 

5、一直使用 HTTPS

 

不要使用 HTTP协议发布自己的站点和 API,浏览器会对此发出安全警告。

 

6、不要使用不安全和弱加密算法

 

随着计算能力的提升,弱的密钥已经无法对抗暴力破解。某些公司已经将一些加密算法列入不可使用清单之列。

 

- SHA-1

- 1024位 RSA 或 DSA

- 160位 ECDSA 

- 80/112-bit 2TDEA 

- MD5

 

7、以白名单方式处理可执行代码

 

如果在流程中会存在一些代码运行,它们是由 APP 或 API 的用户传入的,也可能是用户输入后生成的,这些都需要我们将要执行的命令列入白名单。

 

例如,要列出服务器上的目录:ls /dir,此时 API 应该处理白名单后转义用户输入的标签。

 

总结

 

我们可以大多数的安全编码实践分为4-5个范式,包括但不限于加密、缗码、白名单、最低权限,不要信任用户的输入内容。

 

如果你的团队采用了这些编码最佳实践,可大降低应用软件安全威胁之风险。 

 

 

 

编译:洛逸

来源:https://dzone.com/articles/practical-secure-coding-practices