安全读取用户输入的最佳方式是什么?
What is the best way to safely read user input?
让我们考虑一个接收 JSON 对象的 REST 端点。 JSON 字段之一是一个字符串,所以我想验证没有收到恶意文本。
@ValidateRequest
public interface RestService {
@POST
@Consumes(APPLICATION_JSON)
@Path("endpoint")
void postData (@Valid @NotNull Data data);
}
public class Data {
@ValidString
private String s;
// get,set methods
}
我正在通过 @ValidString
使用 bean 验证框架将验证委托给 ESAPI 库。
@Override
public boolean isValid (String value, ConstraintValidatorContext context) {
return ESAPI.validator().isValidInput(
"String validation",
value,
this.constraint.type(),
this.constraint.maxLength(),
this.constraint.nullable(),
true);
}
此方法规范化值(即删除加密),然后根据 ESAPI 配置中提供的正则表达式进行验证。正则表达式对问题来说并不那么重要,但它主要将 'safe' 个字符列入白名单。
到目前为止一切都很好。但是,在某些情况下,我需要接受 'less' 个安全字符,例如 %
、"
、<
、>
等,因为传入的文本是来自最终用户的自由文本输入字段。
是否有这种 String
清理的已知模式?如果 SQL 查询被认为是安全的(例如使用绑定变量),什么样的文本会导致服务器端问题?如果用户想要存储 <script>alert("Hello")</script>
作为他的描述,并且在某个时候将被发送回客户端怎么办?我是否将其存储在数据库中?这是客户端的问题吗?
处理来自用户的文本时,最佳做法是仅将已知字符集列入白名单,如您所述。但这不是完整的解决方案,因为有时它不起作用,正如您有时指出的那样 "dangerous" 字符是有效字符集的一部分。
发生这种情况时,您需要非常注意处理数据的方式。我和评论者都建议尽可能长时间地保持用户的原始数据处于原始状态。安全地处理数据将是为目标使用适当的功能domain/output。
SQL
将自由格式字符串放入 SQL 数据库时,最佳做法是使用准备好的语句(在 java 中,这是 PreparedStatement 对象或使用将自动参数化数据。
要阅读有关 SQL 注入攻击和其他形式的注入攻击(XML、LDAP 等)的更多信息,我推荐 OWASPS Top 10 - A1 Injections
XSS
您还提到了将这些数据输出到客户端时要做什么。在这种情况下,我想确保 html 为正确的上下文对输出进行编码,也就是上下文输出编码。 ESAPI 对此有 Encoder Class/Interface。需要注意的重要一点是数据将输出到哪个上下文(HTML Body,HTML Attribute,JavaScript,URL,等等)。每个区域将被不同地编码。
以输入为例:<script>alert('Hello World');<script>
示例编码输出:
- HTML:
<script>alert('Hello World');<script>
- JavaScript:
\u003cscript\u003ealert(\u0027Hello World\u0027);\u003cscript\u003e
URL: %3Cscript%3Ealert%28%27Hello%20World%27%29%3B%3Cscript%3E
- 表格URL:
%3Cscript%3Ealert%28%27Hello+World%27%29%3B%3Cscript%3E
- CSS:
[=15=]003Cscript[=15=]003Ealert[=15=]0028[=15=]0027Hello[=15=]0020World[=15=]0027[=15=]0029[=15=]003B[=15=]003Cscript[=15=]003E
- XML:
<script>alert('Hello World');<script>
有关 XSS 的更多阅读,请参阅 OWASP Top 10 - A3 Cross-Site Scripting (XSS)
让我们考虑一个接收 JSON 对象的 REST 端点。 JSON 字段之一是一个字符串,所以我想验证没有收到恶意文本。
@ValidateRequest
public interface RestService {
@POST
@Consumes(APPLICATION_JSON)
@Path("endpoint")
void postData (@Valid @NotNull Data data);
}
public class Data {
@ValidString
private String s;
// get,set methods
}
我正在通过 @ValidString
使用 bean 验证框架将验证委托给 ESAPI 库。
@Override
public boolean isValid (String value, ConstraintValidatorContext context) {
return ESAPI.validator().isValidInput(
"String validation",
value,
this.constraint.type(),
this.constraint.maxLength(),
this.constraint.nullable(),
true);
}
此方法规范化值(即删除加密),然后根据 ESAPI 配置中提供的正则表达式进行验证。正则表达式对问题来说并不那么重要,但它主要将 'safe' 个字符列入白名单。
到目前为止一切都很好。但是,在某些情况下,我需要接受 'less' 个安全字符,例如 %
、"
、<
、>
等,因为传入的文本是来自最终用户的自由文本输入字段。
是否有这种 String
清理的已知模式?如果 SQL 查询被认为是安全的(例如使用绑定变量),什么样的文本会导致服务器端问题?如果用户想要存储 <script>alert("Hello")</script>
作为他的描述,并且在某个时候将被发送回客户端怎么办?我是否将其存储在数据库中?这是客户端的问题吗?
处理来自用户的文本时,最佳做法是仅将已知字符集列入白名单,如您所述。但这不是完整的解决方案,因为有时它不起作用,正如您有时指出的那样 "dangerous" 字符是有效字符集的一部分。
发生这种情况时,您需要非常注意处理数据的方式。我和评论者都建议尽可能长时间地保持用户的原始数据处于原始状态。安全地处理数据将是为目标使用适当的功能domain/output。
SQL
将自由格式字符串放入 SQL 数据库时,最佳做法是使用准备好的语句(在 java 中,这是 PreparedStatement 对象或使用将自动参数化数据。
要阅读有关 SQL 注入攻击和其他形式的注入攻击(XML、LDAP 等)的更多信息,我推荐 OWASPS Top 10 - A1 Injections
XSS
您还提到了将这些数据输出到客户端时要做什么。在这种情况下,我想确保 html 为正确的上下文对输出进行编码,也就是上下文输出编码。 ESAPI 对此有 Encoder Class/Interface。需要注意的重要一点是数据将输出到哪个上下文(HTML Body,HTML Attribute,JavaScript,URL,等等)。每个区域将被不同地编码。
以输入为例:<script>alert('Hello World');<script>
示例编码输出:
- HTML:
<script>alert('Hello World');<script>
- JavaScript:
\u003cscript\u003ealert(\u0027Hello World\u0027);\u003cscript\u003e
URL:%3Cscript%3Ealert%28%27Hello%20World%27%29%3B%3Cscript%3E
- 表格URL:
%3Cscript%3Ealert%28%27Hello+World%27%29%3B%3Cscript%3E
- CSS:
[=15=]003Cscript[=15=]003Ealert[=15=]0028[=15=]0027Hello[=15=]0020World[=15=]0027[=15=]0029[=15=]003B[=15=]003Cscript[=15=]003E
- XML:
<script>alert('Hello World');<script>
有关 XSS 的更多阅读,请参阅 OWASP Top 10 - A3 Cross-Site Scripting (XSS)