admin 管理员组文章数量: 887021
2024年2月28日发(作者:扒站工具整站)
安全开发规范
1) 对服务器资源访问进行校验
推荐方式:对公开的访问url以/pub/开始,在webapp中建立filter,对所有非/pub/的访问url进行过滤,未登陆用户不允许访问,对于服务器的图片以及css,js资源,应当以nginx作为动静分离
2) Nginx中的特殊文件后缀.git|.svn|.cvs进行屏蔽,例如
location ~ ^(.*)/.svn/{
deny all;
}
3) 身份认证应避免客户端向服务器发送明文密码,在非ssl环境下,应当采用md5+salt,盐长度大于5且数字与大小写英文结合方式,服务器在收到加密的密码后,在存储与验证前进行二次加密对比
4) 对于敏感信息(如身份证与银行卡),服务器在写入最终存储前,应当进行可逆加密,如DES加密/解密,将密钥放于内网服务器上,测试环境应当无法获得生产环境密钥,即解决研发人员盗走数据的风险
5) 身份验证提示信息应当为”用户名和密码错误”,尽量避免”用户名错误”和”密码错误”
6) 接口应当尽量使用HTTP POST方式提交数据,避免使用GET方式,非内部接口提供数据应当使用https
7) 在连续多次失败后(通常为5次以上),执行锁定帐户操作,锁定时间应不小于30分钟,避免被尝试暴力破解与密码猜测
应避免弱密码,8-20位以内,数字与大小写字母结合方式,由于前后台非明文传输,弱密码检测应当在客户端与js端完成
8) 发送短信验证码、邮件应当以验证码拦截非法请求,验证码为4-6位数字与字母结合,带干扰线,验证码应当在一次验证后,无论正确与错误都重新生成,单位时间内(通常为2分钟)请求验证码的次数应当在10次以内,避免验证码被猜测攻击
9) 使用邮件找回密码功能,邮件有效时长应当小于2小时
10) 除非业务需要,应当尽量避免同一ID的并发登陆,即同一ID后登录用户应当踢掉前用户
11) 用户会话标识token应当在http的cookie中或head的其他位置,不允许将会话标识拼接入GET请求的参数或url中
12) 登陆日志的记录:将用户,登陆时间,登陆ip记录入系统日志或存储与关系型与非关系型数据库,可异步写入
13) Nginx日志应当尽量输出"$request_time" "$upstream_response_time"用来定位响应慢请求
14) 系统白名单:对于关键性业务,内部通信应当采用ip内部白名单方式,仅受限ip可访问,ip白名单可以采用iptables防火墙拦截与filter进行ip过滤方式
15) 加入XSS过滤filter,原理:采用Decorator模式,用继承HttpServletRequestWrapper的XssHttpServletRequestWrapper在getParameter中检查原参数,检测xss关键字,同理建立防SQL注入filter与防webshell的filter,系统应尽量避免jsonp这种远程跨域调用
16) 加入防CC攻击filter,动静分离后对ip进行计数,每2分钟清除ip计数,计数采用concurrentHashMap
用户ID的concurrentHashMap
17) 检测请求页面的referer,除公开页面(/pub/)外,所有需要登陆的页面,检测来源网页,对于关键页面,检测上级来源页面,对于非法机器模拟请求进行拦截
18) 防SQL注入攻击代码:DB层代码应尽量采用PreparedStatement,避开拼接sql以及直接使用statement,所有参数使用setString/setObject方式来替代问号,对于使用模糊查询,使用类似select * from user where username like %?%,之后传参,对于mybatis中${xxx}为直接参与编译的代码,应当慎重使用,尽量使用#{xxx}来进行参数写入,如实在无法避免,也需确认参数不来自于前端的输入,尽量使用mybatis或activerecord等封装好底层jdbc的方式,避免自己手动获得Connection以导致会话未关闭引起的连接数超限制
19) 对于kvdb,类似memcache与redis,应当尽量避免暴露外网端口,内部访问需要进行iptables的白名单设置,对使用者连接时,设置用户名密码,本身kvdb是允许匿名用户直连,此处应当运维方控制
20) 系统使用activemq以及其他类mq时,mq应当避免暴露任何外网端口,管理密码需要重置为复杂密码
21) 系统使用solr,elasticsearch等应当使用iptables控制访问权限,因为本身全文检索服务不提供用户权限管理模块
22) 系统使用mongodb时,运维应当关闭外网访问端口,采用用户名密码方式内网连接
23) 系统应当尽量少使用类似FCKEditor之类的富文本编辑器,如若使用,应去掉文件上传相应代码,或对文件上传进行控制,后台通过以下手段防止漏洞
① 检查用户是否登陆且有上传权限,记录上传日志
② 检查限制上传文件大小
③ 检查文件后缀(.jpg/.gif/.png/.doc/.docx/.xls/.ppt等非可执行文件)
④ 文件服务器尽量采用linux,将文件存储于/store/目录/store目录的权限为可读写,不可执行
⑤ Web应用服务器采用appuser账户启动,对本地文件夹/store/可读写,对root用户文件不可读写执行
24) Web系统应对所有的用户输入参数进行校验,去除非法与越界参数,这步验证为彻底去除xss注入的关键
25) 系统选型应避免struts2,jboss4以及其他已经发现漏洞较多的web容器和框架
26) 系统应使用log4j或slf4j来进行日志输出,避免使用n进行输出信息,日志输出时,应避开敏感信息,日志级别建议:
TRACE 底层细节执行事件以及触发的执行过程
DEBUG 调试应用程序细粒度事件
INFO 突出强调应用程序的运行过程
WARN 表明会出现潜在错误的情形
ERROR 发生错误事件,但不影响系统的继续运行
FATAL 严重的错误事件将会导致应用程序的退出
27) 403/404页面与500页面需要自定义html页面,避免由于tomcat直接打印堆栈输出敏感信息
28) 禁止表单中的自动填充功能,因为表单中可能包含敏感信息,包括身份验证信息
29) 禁止客户端缓存网页,因为可能包含敏感信息。”Cache-Control: no-store”,可以和H”Pragma: no-cache”一起使用
30) Android,iOS以及H5中不存储用户密码,必要时可存储会话标识
31) try{}catch{}在catch中应当至少tackTrace()用于追踪问题堆栈,对于上层调用或远程调用,应当继续throw e对上层进行异常输出,不在错误响应中泄露敏感信息,包括:系统的详细信息、会话标识符或者帐号信息
32) 尽量避免调用系统脚本进行数据操作以避免触发webshell漏洞,例如在某些条件下使用linux的date -s与lftp命令
33) 对于web应用,非底层通信模块,尽量避免使用synchronized关键字进行同步,以及lock,对于IO以及高速响应的数据通信中,例如nio,netty等,需要单jvm内进行数据锁定以及同步操作的,可以使用多线程同步关键字,对于跨jvm需要网络锁进行同步的,尽量使用db的悲观锁或乐观锁,适不同业务,通常采用乐观锁,或采用redis等带有原子操作的存储
34) 尽量避免使用vector,hashtable,需要同步时采用rent包下的类来处理
35) 建立工程尽量使用maven工程,用以避免jar文件混乱,输出部署jar应当以ant脚本或maven脚本进行编译
36) Mysql 基本规则:
① 单表记录控制在1000w
② 字段尽量在20个以内
③ Id为bigint自增
④ Tinyint类型的deleted字段作为伪删除标记
⑤ 有默认值为CURRENT_TIMESTAMP的Timestamp时间戳
⑥ 字段避免默认为NULL
⑦ 查询应当能落到索引上,索引在3个以内比较合适,合理使用索引,mysql会判断使用索引如仍需扫描超过全量20%的情况下,会走全表扫描
⑧ 执行select前进行explain检查是否走了全表扫描
⑨ 对于需要全文检索的数据,将数据同步入lucene
⑩ 尽可能避免触发器与存储过程
11 清空表时采用truncate table 速度快于delete,但同时会把auto_increment的值恢复为1
12 数据表使用innodb存储引擎
13 对于部分特殊场景,不需要事务,单线程写入数据量较大的表可采用myisam引擎
14 对于类似key-->map型数据,可以使用handlesocket方式直接操作innodb
15 OLTP与OLAP分割处理,对于实时高速业务应用OLTP,对于分析性数据,可以采用数据库从库方式进行读写分离
16 强业务一致场景只能走到主库操作,例如:交易完成后立即查询
17 表超过一定量(通常为单表额度1000w),可以对数据进行分库分表以及分区表操作
18 SQL查询应避免select *,采用select 具体列来替代
19 Where 条件中使用IN 与UNION 来替代OR
20 建立视图时避免使用union 与union ALL ,会导致索引失效
21 分页时采用where id>上一次最大id order by id asc limit 条数,来替代limit 偏移量,条数
22 避免使用临时内存表,临时内存表建立通常会消耗0.2秒左右,造成并发响应缓慢
23 避免使用复杂sql来响应前端用户请求,考虑数据变化不明显时,可以采用系统缓存来定时更新sql结果
24 主库写频率较高时,去掉query_cache,数据库querycache为全局锁,频繁的写入会导致锁定时间过长
25 使用decimal而不是double和float
26 对于需要使用乐观锁的表加入int version类型字段
27 函数尽量不要做为条件变量,例如避免使用select from user where
date_format(_time,”yyyyMMdd”)>20150101,而是使用select from user
where _time>’2015-01-01’,原因为如果reg_time为索引字段,使用函数后将无法落到索引上
28 可以使用外键约束,但不推荐使用级联删除
29 Mysql中建立用户应明确ip范围,权限只针对某库某表
30 Mysql监听地址仅为内网
31 Binlog仅运维人员可以接触
37) Filter中使用ThreadLocal时应当用try{}finally{}在finally中将threadLocal的set的变量清空,以避免线程池中变量被下次其他用户使用
38) 对于非线程安全的类的使用,例如SimpleDateFormat,NumberFormat可以采用ThreadLocal或在作用域内单独初始化,甚至使用时进行clone方式
39) 对于较复杂的对象,初始化时会导致线程阻塞,同步的对象,例如Calendar,不使用new
进行创建,使用clone方式进行分配内存空间,可避免线程同步
40) 不推荐使用ehcache和oscache作为二级缓存,原因在于都是线程同步导致系统变慢,少量的缓存走jvm的concurrentHashmap,大量的走redis或memcache
41) Spring mvc中controller尽量设置@Scope("prototype")以避免由于单例bean导致的数据冲突
42) Java操作数据库通常使用spring的事务配置,事务传播级别为PROPAGATION_REQUIRED,即当前没有事务时创建新事务,对于service层进行方法名称匹配时,find*/get*/select*为只读方法,对数据库的数据源配置以readonly方式,仅支持select操作,事务传播级别为无事务
43) Jdk6之后,系统允许动态编译生成运行时class文件并加载到classloader中,非性能要求极致类应用不允许使用
44) Jdk可以动态调用js脚本,js脚本中可以任意调用java的类涉及系统安全与信息泄露,非极端场景不允许使用
45) 事务隔离级别通常为repeatable,可重复读
46) 尽量避免以select ... for update 方式锁定数据,悲观锁方式当无法落到索引情况下,将会导致全表锁,且容易导致死锁发生,在场景允许的情况下,事务隔离级别为可重复读,使用乐观锁,即update .... Where version=当前版本,利用返回值是否为1来判断是否发生了并发冲突
47) 在高IO操作,例如写硬盘文件,采用ssd硬盘,内存映射,内存盘方式提高速度,使用内存映射应当循环利用文件块以避免内存泄漏
48) 尽量避免使用webservice,原因为非轻量级,解析与序列化速度慢,可使用restful或远程RPC(dubbo)来替代,所有内部通信组件,应当只监听内网地址,并通过内部ip白名单与iptables控制访问地址,例如dubbo应设定host
49) Zookeeper通过
clientPortBindAddress=内网地址
clientPortAddress=内网地址
来控制避免暴露外网
50) Tomcat应当8080,8009,8005端口应绑定内网地址
51) 所有java进程在上生产环境中关闭远程调试端口
52) 尽量避免java中直接调用c++,原因为jni/jna通信速度慢且容易引起系统崩溃,且c++
的dll或so库导致的内存泄漏难以察觉,如必须,可以采用socket,或在同一台linux服务器上进行unixsocket调用
53) 门户网站首页应当用nginx cache或者varnish静态化,
① 页面保持在200k以内,开启nginx压缩
② 将css,图片以及变化不大的js放于CDN,图片需要经过压缩,多个小图片合成为整个大图
③