tencent / secguide Goto Github PK
View Code? Open in Web Editor NEW面向开发人员梳理的代码安全指南
License: Other
面向开发人员梳理的代码安全指南
License: Other
1、问题描述
rand类使用srand()初始化也会产生一些逻辑漏洞,比如以下示例:
如果使用该随机数生成验证码时,可能会导致产生生成的随机数相同,从而产生的多个验证码相同,导致逻辑漏洞的产生。
而且rand本身随机性就不高,可直接禁用该函数。
2、解决建议
可以使用libsodium库提供的一组函数,来产生不可预测的数据。可以使用该库的随机数生成函数来生成安全随机数,
如示例(网上copy的,没验证过):
#include "sodium.h"
int foo() {
char myString[32];
int myInt;
randombytes_buf(myString, 32);
/* myString will be a string of 32 random bytes /
myInt = randombytes_uniform(10);
/ myInt will be a random number between 0 and 9 */
}
jackson版本应不低于2.11.x
禁用 enableDefaultTyping 函数
禁用 JsonTypeInfo 注解
如需使用jackson快速存储数据到redis中应使用 activateDefaultTyping + 白名单过滤器
// jackson白名单过滤
ObjectMapper om = new ObjectMapper();
BasicPolymorphicTypeValidator validator = BasicPolymorphicTypeValidator.builder()
// 信任 com.china. 包下的类
.allowIfBaseType("com.china.")
.allowIfSubType("com.china.")
// 信任 Collection、Map 等基础数据结构
.allowIfSubType(Collection.class)
.allowIfSubType(Number.class)
.allowIfSubType(Map.class)
.allowIfSubType(Temporal.class)
.allowIfSubTypeIsArray()
.build();
om.activateDefaultTyping(validator,ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
1.6 【必须】不应当把用户可修改的字符串作为printf系列函数的“format”参数
如果用户可以控制字符串,则通过 %n %p 等内容,最坏情况下可以直接执行任意恶意代码。
在以下情况尤其需要注意: WIFI名,设备名……
错误:
snprintf(buf, sizeof(buf), wifi_name);
正确:
snprinf(buf, sizeof(buf), "%s", wifi_name); // 这里应该是 snprintf,少个 t
SpringBoot Actuator 如果不进行任何安全限制直接对外暴露访问接口,可导致敏感信息泄露甚至恶意命令执行。
解决方案:
// 参考版本 springboot 2.3.2
// pom.xml 配置参考
<!-- 引入 actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- 引入 spring security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
// application.properties 配置参考
#路径映射
management.endpoints.web.base-path=/lhdmon
#允许访问的ip列表
management.access.iplist = 127.0.0.1,192.168.1.100,192.168.2.3/24,192.168.1.6
#指定端口
#management.server.port=8081
#关闭默认打开的endpoint
management.endpoints.enabled-by-default=false
#需要访问的endpoint在这里打开
management.endpoint.info.enabled=true
management.endpoint.health.enabled=true
management.endpoint.env.enabled=true
management.endpoint.metrics.enabled=true
management.endpoint.mappings.enabled=true
#sessions需要spring-session包的支持
#management.endpoint.sessions.enabled=true
#允许查询所有列出的endpoint
management.endpoints.web.exposure.include=info,health,env,metrics,mappings
#显示所有健康状态
management.endpoint.health.show-details=always
使用srand(time(0))
从某种程度上讲和不使用srand
一样不安全,只要攻击者可以准确计算时间到秒即可。
应从更不可预测的熵源中选取种子而不是时间种子。
【错误写法】跟【安全示例】只有注释部分不一样,建议改为更容易理解的ORM形式(如用占位符?
),否则仍然容易产生漏洞。
1、问题描述
数据输出规范,属于数据业务安全范畴,并非Node语言独立特性。并浏览了Java、Go等的安全规范中,也并未包含此说明(或描述不统一)。
2、解决建议
可以新增一个数据安全类的md文档,所有服务端数据出输范畴的安全描述,都可以外联到这个文档上。
"log_m_essage" seems is a typo.
Should replace with "log_message"
1、问题描述
java 代码安全规范的【1.2.1 条】 文件类型限制 需补充
2、解决建议
通过后缀名进行文件类型校验不总是可靠的,建议补充魔数的校验方式
通用解决方案:
定义白名单的文件类型魔数枚举类,通过 commons-io 的 FileFilterUtils 类的 magicNumberFileFilter 进行过滤。
Hi,
Great job on these guides! I have always been interested in security, I regularly research it, and I keep updated with trends. Even though I can't read Chinese I can easily read the code and know what security features you are showing. I consider your guide to be of both great quality and in a compact format that allows for developers at any skill level to effectively use the content to secure their apps. Even for experienced developers like myself your compact format can be used as a good checklist when reviewing an app.
Do you have plans to translate this content into other languages or would you consider it? I feel this guide would be of great benefit to developers for many other languages. I'm a native english speaker so I'll include a Google Translate text as well. Personally I've worked with several open source projects where Google Translate was used (other options can be used as well) then a native translator was able to provide corrections and updates so the process can be completed without too much time.
Keep up the good work!
Conrad
你好,
在这些指南上做得很好!我一直对安全性感兴趣,我会定期对其进行研究,并且会随时了解最新趋势。即使我不会读中文,也可以轻松阅读代码并知道您所显示的安全功能。我认为您的指南质量很高,而且格式紧凑,可以使任何技能水平的开发人员都可以有效地使用内容来保护其应用程序。即使对于像我这样的经验丰富的开发人员,您的紧凑格式也可以用作检查应用程序时的良好核对清单。
您是否打算将这些内容翻译成其他语言,或者您会考虑使用?我觉得该指南对于许多其他语言的开发人员将大有裨益。我是说英语的母语人士,因此我还将包括Google翻译文本。就我个人而言,我曾与几个使用Google翻译(也可以使用其他选项)的开源项目一起工作,然后本机翻译程序可以提供更正和更新,因此可以在没有太多时间的情况下完成该过程。
保持良好的工作!
Conrad
1、问题描述
java 代码安全规范的【1.9.1 条】 返回信息最小化 需补充
2、解决建议
应补充下列编码规范:
解决方案1:
@Controller
class UserController {
//禁止在url中使用业务变量,以防止篡改导致的越权
@PostMapping("/user")
public UserEntity getUser(@RequestParam("id") String id) {
//返回用户所有字段内容,可能包括敏感字段
return userService.findById(id).get();
}
}
@Controller
class UserController {
@InitBinder
public void initBinder(WebDataBinder binder, WebRequest request){
//限制返回给用户的字段
binder.setAllowedFields(["username","password"]);
}
}
解决方案2:
@Controller
class UserController {
//禁止在url中使用业务变量,以防止篡改导致的越权
@PostMapping("/user")
public UserEntity getUser(@RequestParam("id") String id) {
//返回用户所有字段内容,可能包括敏感字段
return userService.findById(id).get();
}
}
class UserEntity {
@Id
private Long id;
private String username;
// 如果使用jackson,可以使用@JsonIgnore禁止某字段参加格式化
// 在某字段的get方法上使用@JsonIgnore对应禁止序列化,在set方法方法上使用@JsonIgnore对应禁止反序列化
// 或者使用@JsonIgnoreProperties(value = "{password}")禁止某字段参与格式化
@JsonIgnore
private String password;
}
攻击者可以构造恶意js注入到js引擎执行恶意代码,所以在java中使用js引擎应使用安全的沙盒模式执行js代码。
脆弱代码:
public void runCustomTrigger(String script) {
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("JavaScript");
// 不执行安全校验,直接eval执行可能造成恶意的js代码执行
engine.eval(script);
}
解决方案:
java 8 或者 8 以上版本使用 delight-nashorn-sandbox 组件
<dependency>
<groupId>org.javadelight</groupId>
<artifactId>delight-nashorn-sandbox</artifactId>
<version>[insert latest version]</version>
</dependency>
// 创建沙盒
NashornSandbox sandbox = NashornSandboxes.create();
// 沙盒内默认禁止js代码访问所有的java类对象
// 沙盒可以手工授权js代码能访问的java类对象
sandbox.allow(File.class);
// eval执行js代码
sandbox.eval("var File = Java.type('java.io.File'); File;")
java 7 使用 Rhino 引擎
public void runCustomTrigger(String script) {
// 启用 Rhino 引擎的js沙盒模式
SandboxContextFactory contextFactory = new SandboxContextFactory();
Context context = contextFactory.makeContext();
contextFactory.enterContext(context);
try {
ScriptableObject prototype = context.initStandardObjects();
prototype.setParentScope(null);
Scriptable scope = context.newObject(prototype);
scope.setPrototype(prototype);
context.evaluateString(scope,script, null, -1, null);
} finally {
context.exit();
}
}
如果应用程序未正确校验用户输入的数据,则恶意用户可能会破坏应用程序的逻辑以执行针对客户端或服务器端的攻击。
脆弱代码1:
// 攻击者可以提交 lang 的内容为:
// en&user_id=1#
// 这将使攻击者可以随意篡改 user_id 的值
String lang = request.getParameter("lang");
GetMethod get = new GetMethod("http://www.host.com");
// 攻击者提交 lang=en&user_id=1#&user_id=123 可覆盖原始 user_id 的值
get.setQueryString("lang=" + lang + "&user_id=" + user_id);
get.execute();
解决方案1:
// 参数化绑定
URIBuilder uriBuilder = new URIBuilder("http://www.host.com/viewDetails");
uriBuilder.addParameter("lang", input);
uriBuilder.addParameter("user_id", userId);
HttpGet httpget = new HttpGet(uriBuilder.build().toString());
脆弱逻辑2:
订单系统计算订单的价格
步骤1:
订单总价 = 商品1单价 * 商品1数量 + 商品2单价 * 商品2数量 + ...
步骤2:
钱包余额 = 钱包金额 - 订单总价
当攻击者将商品数量都篡改为负数,导致步骤1的订单总价为负数。而负负得正,攻击者不仅买入了商品并且钱包金额也增长了。
解决方案2:
应在后台严格校验订单中每一个输入参数的长度、格式、逻辑、特殊字符以及用户的权限。
编写编码规范应注意,开发人员很讨厌东一个规则西一个规则,最好把所有安全校验的逻辑写到一个接口示例中,保证一次性能看完所有的相关安全问题。
1、问题描述
java 代码安全规范的【1.2.4 条】 避免路径穿越 需补充
import org.apache.commons.io.FilenameUtils;
@GET
@Path("/images/{image}")
@Produces("images/*")
public Response getImage(@javax.ws.rs.PathParam("image") String image) {
// 首先进行逻辑校验,判断用户是否有权限访问接口 以及 用户对访问的资源是否有权限
// 过滤image变量中的 ../ 或 ..\
File file = new File("resources/images/", FilenameUtils.getName(image));
if (!file.exists()) {
return Response.status(Status.NOT_FOUND).build();
}
return Response.ok().entity(new FileInputStream(file)).build();
}
XPath注入风险类似于SQL注入,如果XPath查询包含不受信任的用户输入,则可能会暴露完整的数据源。这可能使攻击者可以访问未经授权的数据或恶意修改目标XML。
下面以登录验证中的模块为例,说明 XPath注入攻击的实现原理。
在应用程序的登录验证程序中,一般有用户名(username)和密码(password) 两个参数,程序会通过用户所提交输入的用户名和密码来执行授权操作。
若验证数据存放在XML文件中,其原理是通过查找user表中的用户名 (username)和密码(password)的结果进行授权访问。
例存在user.xml文件如下:
<user>
<firstname>Ben</firstname>
<lastname>Elmore</lastname>
<loginID>abc</loginID>
<password>test123</password>
</user>
<user>
<firstname>Shlomy</firstname>
<lastname>Gantz</lastname>
<loginID>xyz</loginID>
<password>123test</password>
</user>
则在XPath中其典型的查询语句如下:
//users/user[loginID/text()='xyz'and password/text()='123test']
正常用户传入 login 和 password,例如 loginID = 'xyz' 和 password = '123test',则该查询语句将返回 true。但如果恶意用户传入类似 ' or 1=1 or ''=' 的值,那么该查询语句也会得到 true 返回值,因为 XPath 查询语句最终会变成如下代码:
//users/user[loginID/text()=''or 1=1 or ''='' and password/text()='' or 1=1 or ''='']
脆弱代码:
public int risk(HttpServletRequest request,
Document doc, XPath xpath ,org.apache.log4jLogger logger) {
int len = 0;
String path = request.getParameter("path");
try {
XPathExpression expr = xpath.compile(path);
Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
len = nodes.getLength();
} catch (XPathExpressionException e) {
logger.warn("Exception", e);
}
return len;
}
解决方案:
public int fix(HttpServletRequest request,
Document doc, XPath xpath ,org.apache.log4j.Logger logger) {
int len = 0;
String path = request.getParameter("path");
try {
// 使用过滤函数
String filtedXPath = filterForXPath(path);
XPathExpression expr = xpath.compile(filtedXPath);
Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
len = nodes.getLength();
} catch (XPathExpressionException e) {
logger.warn("Exception", e);
}
return len;
}
// 限制用户的输入数据,尤其应限制特殊字符
public String filterForXPath(String input) {
if (input == null) {
return null;
}
StringBuilder out = new StringBuilder();
for (int i = 0; i < input.length(); i++) {
char c = input.charAt(i);
if (c >= 'A' && c <= 'Z') {
out.append(c);
} else if (c >= 'a' && c <= 'z') {
out.append(c);
} else if (c >= '0' && c <= '9') {
out.append(c);
} else if (c == '_' || c == '-') {
//限制特殊字符的使用
out.append(c);
} else if (c >= 0x4e00 && c <= 0x9fa5) {
//允许汉字使用
out.append(c);
}
}
return out.toString();
}
1、问题描述
java 代码安全规范的 1.5.4 外部输入拼接到HTTP响应头中需进行过滤 需补充
2、解决建议
应补充下列编码规范:
public void risk(HttpServletRequest request, HttpServletResponse response) {
String val = request.getParameter("val");
try {
int value = Integer.parseInt(val);
}
catch (NumberFormatException e) {
val = val.replace("\r", "");
val = val.replace("\n", "");
log.info(""Failed to parse val = "" + val);
//不要直接 printStackTrace 输出错误日志
}
}
对用户输入数据绑定到对象时如不做限制,可能造成攻击者恶意覆盖用户数据
脆弱代码:
@javax.persistence.Entity
class UserEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
private Long role;
}
@Controller
class UserController {
@PutMapping("/user/")
@ResponseStatus(value = HttpStatus.OK)
public void update(UserEntity user) {
// 攻击者可以构造恶意user对象,将id字段构造为管理员id,将password字段构造为弱密码
// 如果鉴权不完整,接口读取恶意user对象的id字段后会覆盖管理员的password字段成为弱密码
userService.save(user);
}
}
解决方案:
@Controller
class UserController {
@InitBinder
public void initBinder(WebDataBinder binder, WebRequest request){
// 对允许绑定的字段设置白名单,阻止其他所有字段
binder.setAllowedFields(["role"]);
}
}
@Controller
class UserController {
@InitBinder
public void initBinder(WebDataBinder binder, WebRequest request){
// 对不允许绑定的字段设置黑名单,允许其他所有字段
binder.setDisallowedFields(["username","password"]);
}
}
1、问题描述
java 代码安全规范的【1.6 】 OS命令执行 需修改
2、解决建议
应修改下列编码建议:
或过滤转义以下符号:|;&$><(反引号)!
修改为
或过滤转义以下符号: & | ; $ > < ` ' " ! ? #
主要增加一些ctf里,命令执行绕过的技巧中用到的特殊符号
1、问题描述
java 代码安全规范的【1.10.3条】【建议】加锁操作
2、解决建议
应补充下列编码规范:
1、问题描述
Go安全指南的1.2.1【必须】路径穿越检查中所列举的unzipGood例子,存在任意文件写入的问题
// good: 检查压缩的文件名是否包含..路径穿越特征字符,防止任意写入
func unzipGood(f string) bool {
r, err := zip.OpenReader(f)
if err != nil {
fmt.Println("read zip file fail")
return false
}
for _, f := range r.File {
p, _ := filepath.Abs(f.Name)
if !strings.Contains(p, "..") {
ioutil.WriteFile(p, []byte("present"), 0640)
}
}
return true
}
2、解决建议
func Abs(path string) (string, error)
Abs returns an absolute representation of path. If the path is not absolute it will be joined with the current working directory to turn it into an absolute path. The absolute path name for a given file is not guaranteed to be unique. Abs calls Clean on the result.
应当对目标路径的合法性进行校验,而不是检查是否包含..
。
filepath.Abs()自身就已经调用了filepath.Clean(),因此上述函数中的!strings.Contains(p, "..")
是无效的检查。
If possible can this great guide be converted in English so that it can cater wider audience
是否可以提供 C# 安全指南
// Bad
char a[4] = {0};
_snprintf(a, 4, "%s", "AAAA");
foo = strlen(a);
上述代码在MSVC中执行后, a[4] == 'A',因此字符串未以0结尾。
这里的a[4]== 'A' 应该改成a[3]=='A'
如题
1、问题描述
建议采用随机盐+明文密码进行多轮哈希后存储密码。
2、解决建议
【必须】随机盐必须是符合密码学安全的随机数。禁止使用Random类生产。
【必须】随机盐的长度不能太短,建议至少256比特。
【建议】盐值至少和哈希函数的输出一样长
【必须】每次使用的盐必须随机化和一次性,禁止使用共享的随机盐,注册或者修改密码时,都应该使用新的盐值进行加密。
【必须】使用哈希函数必须是sha256或以上
【建议】建议使用受业界认可的慢哈希算法
【建议】多轮的次数应该充分多
【建议】可以记录多轮的次数和加密算法,以便进行后续的维护升级
1、问题描述
1.8.3【建议】哈希算法推荐使用SHA256或更高级别的哈希算法,已获得金融级别的安全保证。
综合国密、**金融移动支付相关规范、等保2.0、等保3.0等相关规范,建议安全认证的使用哈希算法至少SHA256和以上。
2、解决建议
1.8.3【建议】哈希算法推荐使用SHA256或更高级别的哈希算法
3 参考
**金融移动支付
不安全的 Swagger 暴露
Swagger 如果不进行任何安全限制直接对外暴露端访问路径,可导致敏感接口以及接口的参数泄露。
解决方案:
// 测试环境配置文件 application.properties 中
swagger.enable=true
// 生产环境配置文件 application.properties 中
swagger.enable=false
// java代码中变量 swaggerEnable 通过读取配置文件设置swagger开关
@Configuration
public class Swagger {
@Value("${swagger.enable}")
private boolean swaggerEnable;
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
// 变量 swaggerEnable 控制是否开启 swagger
.enable(swaggerEnable)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.tao.springboot.action"))
//controller路径
.paths(PathSelectors.any())
.build();
}
组合使用 cppcheck pvs-studio JetBrains.ReSharper 基本可以发现大多数问题。
日志注入攻击是将未经验证的用户输入写到日志文件中,可以允许攻击者伪造日志条目或将恶意内容注入到日志中。
如果用户提交val的字符串"twenty-one",则会记录以下条目:
INFO: Failed to parse val=twenty-one
HACK: User logged in=badguy
然而,如果攻击者提交包含换行符%0d和%0a的字符串”twenty-one%0d%0aHACK:+User+logged+in%3dbadguy”,会记录以下条目:
INFO: Failed to parse val=twenty-one
HACK: User logged in=badguy
显然,攻击者可以使用相同的机制插入任意日志条目。所以所有写入日志的条目必须去除\r和\n字符。
脆弱代码:
public void risk(HttpServletRequest request, HttpServletResponse response) {
String val = request.getParameter("val");
try {
int value = Integer.parseInt(val);
out = response.getOutputStream();
}
catch (NumberFormatException e) {
e.printStackTrace(out);
log.info(""Failed to parse val = "" + val);
}
}
解决方案:
public void risk(HttpServletRequest request, HttpServletResponse response) {
String val = request.getParameter("val");
try {
int value = Integer.parseInt(val);
}
catch (NumberFormatException e) {
val = val.replace("\r", "");
val = val.replace("\n", "");
log.info(""Failed to parse val = "" + val);
//不要直接 printStackTrace 输出错误日志
}
}
文档中章节 1.1.9【推荐】不使用slice作为函数入参 对于slice的描述不准确,原始内容如下:
slice是引用类型,在作为函数入参时采用的是地址传递,对slice的修改也会影响原始数据。
package main
import "fmt"
func main() {
si := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
fmt.Printf("%v len %d\n", si, len(si))
test1(si)
fmt.Printf("%v len %d\n", si, len(si))
}
func test1(si []int) {
si = append(si[:3], si[4:]...)
}
该代码的运行结果如下:
[1 2 3 4 5 6 7 8 9] len 9
[1 2 3 5 6 7 8 9 9] len 9
从代码示例及运行结果可以看出:
先假设 slice做为参数是引用(或地址)传递 成立。那么在函数内部对slice的操作应当 完整的 反馈在原slice上,即:函数外部slice结构中的数组(array)、长度(len)、容量(cap)这3个都应当发生与之对应的改变。
但实践后的结果与预期不符,也就是说:slice做为参数是引用(或地址)传递 不成立。也就是说:slice作为参数是值传递。
问题一:既然是值传递,那为什么数组内容变了?
因为slice整个结构是值传递,但slice中的数组是个 指针,在进行数据复制的过程中新的slice的数组内容使用的还是 原指针的值,因此函数内slice和外部的slice使用的是 同一份数据。
所以函数内部对 slice 数组的操作也会反馈到函数外的 slice上。
但是长度、容量这两个是整型数值,不是指针类型,因此复制的过程中只是复制的内容,在函数内部的操作也不会影响外部。
附slice底层结构:
type slice struct {
array unsafe.Pointer
len int
cap int
}
以上是个人分析,如果大家有不同结论和分析,欢迎探讨。
正则表达式(Regex)经常遭受拒绝服务(DOS)攻击(称为ReDOS),根据特定的正则表达式定义,当分析某些字符串时,正则表达式引擎可能会花费大量时间甚至导致宕机。
脆弱代码:
符号 | 符号 [] 符号 + 三者联合使用可能受到 ReDOS 攻击:
表达式: (\d+|[1A])+z
需求: 会匹配任意数字或任意(1或A)字符串加上字符z
匹配字符串: 111111111 (10 chars)
计算步骤数: 46342
如果两个重复运算符过近,那么有可能收到攻击。请看以下例子:
例子1:
表达式: .*\d+\.jpg
需求: 会匹配任意字符加上数字加上.jpg
匹配字符串: 1111111111111111111111111 (25 chars)
计算步骤数: 9187
例子2:
表达式: .*\d+.*a
需求: 会匹配任意字符串加上数字加上任意字符串加上a字符
匹配字符串: 1111111111111111111111111 (25 chars)
计算步骤数: 77600
最典型的例子,重复运算符嵌套:
表达式: ^(a+)+$ 处理 aaaaaaaaaaaaaaaaX 将使正则表达式引擎分析65536个不同的匹配路径。
解决方案:
对正则表达式处理的内容应进行长度限制
消除正则表达式的歧义,避免重复运算符嵌套。例如表达式^(a+)+$应替换成^a+$
为什么还没有PHP的呢
1、问题描述
java 代码安全规范的【1.8.1 条】 对称加密 需修改
2、解决建议
应修改下列编码建议:
建议使用AES,秘钥长度256位以上 (多个行业都要求aes最低为256位)
将包含哈希签名的字节数组转换为人类可读的字符串时,如果逐字节读取该数组,则可能会发生转换错误。 所有对于数据格式化的操作应优先使用规范的数据格式化处理机制。
脆弱代码:
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] resultBytes = md.digest(password.getBytes("UTF-8"));
StringBuilder stringBuilder = new StringBuilder();
for(byte b :resultBytes) {
stringBuilder.append( Integer.toHexString( b & 0xFF ) );
}
return stringBuilder.toString();
对于上述功能,哈希值 “0x0679” 和 “0x6709” 都将输出为 “679”
解决方案:
stringBuilder.append(String.format("%02X", b));
当在某些安全关键的上下文中使用可预测的随机值时,可能会导致漏洞。
例如,当该值用作:
脆弱代码:
String generateSecretToken() {
Random r = new Random();
return Long.toHexString(r.nextLong());
}
解决方案:
替换 java.util.Random 使用强度更高的 java.security.SecureRandom
import org.apache.commons.codec.binary.Hex;
String generateSecretToken() {
SecureRandom secRandom = new SecureRandom();
byte[] result = new byte[32];
secRandom.nextBytes(result);
return Hex.encodeHexString(result);
}
// 开启safeMode模式,完全禁用autoType。
1. 在代码中配置
ParserConfig.getGlobalInstance().setSafeMode(true);
如果使用new ParserConfig的方式,需要注意单例处理,否则会导致低性能full gc
2. 加上JVM启动参数
-Dfastjson.parser.safeMode=true
3. 通过fastjson.properties文件配置。
通过类路径的fastjson.properties文件配置,配置方式如下:
fastjson.parser.safeMode=true
// 添加autotype白名单,添加白名单有三种方式
1. 在代码中配置,如果有多个包名前缀,分多次addAccept
ParserConfig.getGlobalInstance().addAccept("com.hyit.pac.client.sdk.dataobject.");
2. 加上JVM启动参数,如果有多个包名前缀,用逗号隔开
-Dfastjson.parser.autoTypeAccept=com.hyit.pac.client.sdk.dataobject.,com.cainiao.
3. 通过类路径的fastjson.properties文件配置,如果有多个包名前缀,用逗号隔开safeMode模式
fastjson.parser.autoTypeAccept=com.hyit.pac.client.sdk.dataobject.,com.cainiao.
希望增加一份iOS的代码安全指南,谢谢!
避免使用不安全的对称加密算法
避免使用不安全的哈希算法
,e.g. MD5倒是出个c#指南啊,腾讯没有c#团队吗
curl%0a1.1.1.1
利用%0a可以绕过命令注入校验!!!
https://github.com/alessio/shellescape/blob/master/shellescape.go
https://pkg.go.dev/github.com/alessio/shellescape#example-Quote
参考PHP中的防范命令注入的两个函数。
PHP对于命令注入漏洞提供了escapeshellarg()和escapeshellcmd()两个函数来进行防御,当然两者针对的场景有区别。
主要是为了防止用户的输入逃逸出“参数值”的位置,变成一个“参数选项”。
处理过程:如果输入内容不包含单引号,则直接对输入的字符串添加一对单引号括起来;如果输入内容包含单引号,则先对该单引号进行转义,再对剩余部分字符串添加相应对数的单引号括起来。
场景功能:
1.确保用户只传递一个参数给命令
2.用户不能指定更多的参数一个
3.用户不能执行不同的命令
主要是防止用户利用shell的一些技巧(如分号、管道符、反引号等)来进行命令注入攻击。
处理过程:如果输入内容中
&#;`|*?~<>^()[]{}$\, \x0A 和 \xFF
等特殊字符会被反斜杠给转义掉;如果单引号和双引号不是成对出现时,会被转义掉。
场景功能:
1.确保用户只执行一个命令
2.用户可以指定不限数量的参数
3.用户不能执行不同的命令
1、问题描述
java 代码安全规范的【1.1.1 条】 SQL语句默认使用预编译并绑定变量 需补充
2、解决建议
应补充下列编码规范:
// 数据搜索时,编码注意要点
// 1)校验搜索数据的业务逻辑:例如搜索用户手机号,应限制输入数据只能输入数字,防止出现搜索英文或中文的无效搜索
// 2)mybatis预编译不会转义 % 符号,应阻止用户输入 % 符号以防止全表扫描
// 3)输入数据长度和搜索频率应进行限制,防止恶意搜索导致的数据库拒绝服务
<select id="getArticles" resultType="Article">
SELECT * FROM article WHERE 1
<if test="searchKeywordType == 'title'">
AND title LIKE CONCAT('%', #{searchKeyword}, '%')
</if>
ORDER BY id DESC
</select>
// 编写 order by 时应使用内置指令,防止$拼接导致sql注入
<select id="findAllList" resultType="Article" >
SELECT * FROM article ORDER BY
<choose>
<when test="page !=null and page != ''">
page asc
</when>
<otherwise>
time desc
</otherwise>
</choose>
</select>
1、问题描述
java 代码安全规范的【1.4条】1.4 XML读写 需补充
2、解决建议
应补充下列编码规范:
// XStream安全编码示例
XStream xStream = newXStream();
// 开启安全模式,安全模式采用白名单限制输入的数据类型
XStream.setupDefaultSecurity(xStream);
// 在白名单内添加一些基本数据类型
xstream.addPermission(NullPermission.NULL);
xstream.addPermission(PrimitiveTypePermission.PRIMITIVES);
xstream.allowTypeHierarchy(Collection.class);
// 在白名单内添加一个包下所有的子类
xstream.allowTypesByWildcard(new String[] {
Blog.class.getPackage().getName()+".*"
});
2.4 【必须】返回栈上变量的地址
这里是不是少了一个不
jep290安全策略:全进程反序列化原则上使用白名单优先的设计模式,只有允许的类才能被反序列化,其它一律被阻止。
// 能被反序列化的流的限制
maxdepth=value // 单次反序列化堆栈最大深度
maxrefs=value // 单次反序列化类的内部引用的最大数目
maxbytes=value // 单次反序列化输入流的字节数上限
maxarray=value // 单次反序列化输入流中数组数上限
// 以下示例介绍了限制反序列化的类名称的配置方法
// 允许唯一类 org.example.Teacher ,输入字节数最大为100,并阻止其它一切的类
jdk.serialFilter=maxbytes=100;org.example.Teacher;!*
// 允许 org.example. 下的所有类,输入字节数最大为100,并阻止其它一切的类
jdk.serialFilter=maxbytes=100;org.example.*;!*
// 允许 org.example. 下的所有类和子类,输入字节数最大为100,并阻止其它一切的类
jdk.serialFilter=maxbytes=100;org.example.**;!*
//允许一切类
jdk.serialFilter=*;
; 作为表达式的分隔符
.* 代表当前包下的所有类
.** 代表当前包下所有类和所有子类
! 代表取反,禁止匹配符号后的表达式被反序列化
* 通配符
jdk11+:%JAVA_HOME%\conf\security\java.security
jdk8: %JAVA_HOME%\jre\lib\security\java.security
java -Djdk.serialFilter=org.example.**;maxbytes=100;!*
Properties props = System.getProperties();
props.setProperty("jdk.serialFilter", "org.example.**;maxbytes=100;!*");
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.