网站安全常见漏洞防范 课程笔记 | 青训营

163 阅读13分钟

什么是漏洞

我们常见的安全事件有数据泄露、服务瘫痪、成果失窃、系统劫持等,漏洞知识的学习一方面可以帮助我们开发时更好的提前规避漏洞、另一方面也可以反向验证企业内部的安全现状。

根据漏洞出现位置的不同可以将网站漏洞分为客户端漏洞和服务端漏洞。常见的服务端漏包含:SQL注入、RCE命令执行、SSRF、文件上传等;常见的客户端漏洞包含:XSS、CSRF、点击劫持、webSocket等。

1.服务端漏洞

1.1 第三方组件漏洞

该类漏洞为使用的第三方组件存在漏洞所致,如:log4j打印日志、fastJson解析json

防护方式:针对java可以选择使用dependency-check-maven插件,检查项目以来的组件是否存在安全漏洞(原理为:把历来的公开的第三方漏洞信息进行整合,对比项目中使用依赖的等级得出报告,帮助我们使用更加安全的依赖版本)

image.png

1.2 SQL注入

什么是SQL注入:我们在使用时没有将SQL的静态模板和我们需要的动态数据进行严格区分,如果在数据项中加入了某些SQL语句关键字(比如说 SELECT、DROP等等),就会改变整个SQL语句的语义,这些SQL语句就可以在数据库写入或读取数据时得到执行,产生不可预期的风险。

比如执行根据id查询一个用户信息这一操作,其sql语句为select * from user where id =,如果传入一个正常的id,语句变成select * from user where id = 1,但若传入参数变成1 or 1=1,那么将会将表中所有的数据查询出来,若再加上一些union操作则更是可以将其他表中的数据查询出来。

如下图所示的代码,图中直接将"raw_order_id"与SQL语句进行了拼接,当对"raw_order_id"使用SQL注入,注入一些union selct语句,可以查询出更多数据,更多数据库更多表的信息。

img

img

一些开发中的错误写法:

1、错误使用语言框架,或者语言框架本身存在安全问题(ORM框架)

例1:java中,使用Mybatis-plus 的危险函数,比如inSql函数,支持直接SQL拼接,存在SQL注入风险,图中的inSql("id", cond),若cond中存在一些外部可控的参数则会导致风险

img

SQL拼接结果:

SELECT `id`,test_int,test_str,create_time,update_time,`test_enum`,`version`,`tenant_id` FROM test_data WHERE (id IN (select id from test_data where version= 0))

SQL注入:

SELECT `id`,test_int,test_str,create_time,update_time,`test_enum`,`version`,`tenant_id` FROM test_data WHERE (id IN (select id from test_data where version= 0 or 1=1))

例2:Java中,使用Mybatis占位符「$」 构建SQL模板

img

使用#:实际的SQL语句:SELECT id,name,pwd,age FROM t_user_info WHERE id = ?(不存在漏洞)

而使用$:实际的SQL语句:SELECT id,name,pwd,age FROM t_user_info WHERE id = 'xx'(存在漏洞)

例3:Golang中的gorm框架,在order中传入用户定义参数十分危险,如:db.Order(param).Find(&product)

正常情况用户输入维度字段即可实现自定义排序param:codeSQL语句:SELECT * FROM products WHERE products.deleted_at IS NULL ORDER BY code

攻击者可以输入SQL语句,改变原始SQL语义param:if(1, sleep(10), ’code’)SQL语句:SELECT * FROM products WHERE products.deleted_at IS NULL ORDER BY if(1, sleep(10), 'code')

总而言之,对SQL注入的防护方式:

1、尽量不要基于DB的Raw方法拼接构造SQL语句,而应该使用预编译、ORM框架

2、使用ORM框架时,应该注意框架中的特性,可能存在不安全的写法导致的SQL注入问题。

3、在复杂场景一定要使用拼接SQL,需要==对外部输入进行转义==。

1.3 命令执行

什么是命令执行漏洞:代码中遇到需要调用某个命令才能完成的功能时候,会涉及到命令拼接,如果命令拼接没有做好安全过滤,那么将会导致命令注入风险,服务器权限将会被控制

例:对于如下代码

img

访问如下接口可查询库存,输入商店id查询库存数量:

img

当修改storeId为「1|id」|为linux中的管道符)时候,即可注入命令id(返回用户相关信息),成功执行:

img

对于命令执行,防护方式与SQL注入类似:

1、对动态的值尽可能设置白名单进行验证。如ping某些地址时,将要使用的地址放入白名单。

2、如果某些位置无法白名单,需要尝试对数据类型进行校验。如对上例中传入的storeId进行数据类型校验。

3、特殊字符黑名单的过滤(将对会造成命令注入的一些字符进行过滤),或者转义。

1.4 越权漏洞

业务场景中的严重漏洞,资源访问或操作时候主体权限没有进行校验就会造成越权问题。越权漏洞可分为三种:未授权、水平越权与垂直越权

1、未授权:未做认证,不需要任何的认证即可访问。

2、水平越权:能操纵同等级别账号中的信息等

例:订单查询功能提供订单id即可查询订单详情,这里攻击者可以遍历不属于自己的orderId来获取其他用户的订单信息

防护方式:涉及资源id尽量不要使用短id(遍历难度较小),同时最重要的一定要做好资源属主校验

3、垂直越权:一些toB系统中通常有角色划分,若出现第权限用户可以访问高权限数据则为垂直越权

例:对于普通用户,访问时由前端直接拦截,提示无权限,但管理员用户可以直接访问的场景, 攻击者可以绕过前端直接尝试访问后端管理员接口,获取数据详情。获取管理员接口的方法较多,如有的api会打包到前端代码中,可从前端Js中拿到、申请一个新的管理员账号,了解前端界面构成即可猜到接口。

防护方式: 如果是简单的场景,可以将接口在路由级别进行分组,对不同的API分组引入Middleware进行权限拦截,Middleware获取当前用户角色以确定是否可以访问此接口。(仅仅通过前端将功能隐藏是不可以的)

1.5 SSRF

SSRF又称服务端请求伪造攻击,指攻击者利用后端服务器为跳板,让后端服务向非预期网络地址(主要指内网地址)发出恶意请求,获取敏感信息或执行恶意操作。

例:争对服务端请求某url或api,获取结果返回的场景,攻击者可将api参数改为内网地址,从而访问内网资源,如改为内网的admin面板http://localhost/admin,即可得到admin的面板,从而执行admin的操作。

防护方式:对url的host进行白名单过滤,若业务场景复杂无法进行白名单过滤,可采用对host解析的ip进行判定是否是内网地址。

1.6 文件上传漏洞

例1:上传文件时上传一些服务端脚本,如.php(php为解释型语言,在服务端能新建文件放入代码就会执行),若不对文件后缀进行限制则会有风险。

例2:找到公开的上传点(如视频创作/文章创作/客服反馈 等),上传恶意文件(恶意视频、图片),获取图片url,然后直接分享url至外部恶意网站或QQ/微信群,造成服务器带宽的消费。

防护方式:

1、限制文件类型:如果系统只需要图片类型,可以从服务端解析文件格式,限制只能传入特定的文件格式。

2、站库分离:应用部署的位置和上传的文件分离,一般可以使用TOS、OSS等进行文件存储。(即使上传了恶意脚本也不会执行)

3、防止图床:对图片访问链接进行限制,包括时间限制,访问身份限制等。

2.客户端漏洞

2.1 开放重定向

某些需要重定向到其他站点的功能,往往在参数中携带需要重定向的 URL ,但实际程序逻辑没有控制好重定向的范围,导致攻击者可以构造恶意链接,诱导用户重定向到恶意站点,实施钓鱼攻击等。

防护方式:对重定向严格进行白名单控制并正确校验匹配白名单。

2.2 XSS(跨站脚本攻击)

本质是一种客户端代码(Script)注入, 攻击者往目标 Web 页面里插入恶意 Script 代码,当用户访问页面(有客户端时需要交互)时,嵌入其中 Web 里面的 Script 代码会被执行,从而达到恶意攻击用户的目的,通常的危害包括窃取用户敏感信息,以用户身份执行敏感操作。

例1:前端代码使用了Vue,会从请求path中读取username,同时使用v-html指令将username直接渲染到Dom中。此时若传入的username带有<svg/onload=alert(1)>则输入后浏览器会弹出弹窗。

例2:将username设置为恶意payload,攻击者通过网站的反馈入口向管理员或运营人员发送恶意链接,让后端管理人员(可以查看所有人的username)可以触发到,攻击者收到管理员/运营人员的Session Cookie后,在浏览器替换cookie为管理员的,从而获取管理员权限

防护方法:

1、输入过滤:对输入的特殊字符进行拦截,禁止前端提交特殊字符。

2、输出过滤:

​ a. 当字符输出到Dom时候,对危险字符进行html 编码或过滤,避免XSS。

​ b. 使用vue/react等框架时候,避免使用危险指令,而应该使用安全指令。v-html/v-text

3、富文本场景:比如文章发布场景,本身是需要提供富文本功能,这时候需要严格限制tag和attribute,可以在代码层面做白名单或者黑名单(如事件型属性)。

4、CSP:用于缓解XSS,理念是对当前站点允许加载什么源的资源、发送什么请求能进行限制。Content-Security-Policy: default-src 'self'; img-src *; media-src example.org example.net; script-src userscripts.example.com,在响应头或xml文件里配置。

2.3 CSRF(跨站请求伪造)

允许攻击者诱导用户访问恶意链接,执行用户非预期执行的操作。危害:用户执行敏感操作,如关注其他用户,或者更改账号的安全邮箱等。

例:网站更改邮箱功能对应接口为一个POST请求https://xxxxx-website.com/change?email=pwned@evil-user.net,攻击者将请求参数里的邮箱改成自己的,根据请求生成CSRF表单,并构造钓鱼链接,再将链接发到网站的论坛里,其他已登录状态的用户点击链接后,就会不知不觉将自己的邮箱改成攻击者的,从而实现盗号。

img

防护方法:防护的核心是判断请求的来源(如拒绝未知软件过来的请求)

1、CSRF tokens: 首次访问时候给客户端传递一个token,客户端每次访问时候都必须带上此token才能访问。

2、SameSite(cookie中的一个属性) cookies有三个等级: Strick -> Lax(Default)(较复杂链接不带cookie) -> None(默认带cookie),核心是禁止某些场景发送第三方cookie。

3、 Referer-based validation: 校验 Referer 来源是否是合法站点。

2.4 点击劫持(clickjacking)

点击劫持(clickjacking)是一种在网页中将恶意代码等隐藏在看似无害或者存在诱导的内容(如按钮)之下,并诱使用户点击的手段,用户点击后往往会执行一些非预期的操作。

例:如有一个删除账号按钮,如果目标站点CSRF防护做的很到位,无法直接构造CSRF钓鱼页面,这时攻击者可能在钓鱼页面iframe原始页面,并且在删除账号的位置覆盖一层诱导性的文字(如win 300$),再将链接给其他用户,用户访问时点击win 300$,实际点击了删除账号按钮。

img

防护方法:防护的核心是保护网站不被非预期的网站 iframe

1、X-Frame-Options指令:DENY / SAMEORIGIN,能控制网站不被iframe

2、CSP: frame-ancestors指令,用于设置允许frame的白名单。Content-Security-Policy: frame-ancestors ;Content-Security-Policy: frame-ancestors 'self' xxxxx.com xxxxx.com

2.5 CORS跨域配置错误

imgimg
简单请求:调用时浏览器自动加上origin头,服务端根据origin头来判断是否要进行调用复杂请求

常见几种CORS错误配置(以需要跨域访问 example.com 所有子域名为例):

1、前缀/后缀/包含/正则匹配:可在原域名的基础上加二级域名如example.com.attack.com、或加其它前缀attackexample.com、attackaexample.com 域名绕过。

2、反射:在Access-Control-Allow-Origin中反射请求的Origin值。理论上可以用任意域名绕过。

3、信任null:攻击者还可以从任意域下通过iframe sandbox构造Origin为null的跨域请求

4、https信任http:http传输存在被劫持篡改可能,攻击者可能通过劫持通信流量注入恶意脚本方式窃取敏感信息。

例:网站个人信息页提供查看个人信息功能,相关接口允许跨域访问且存在配置问题,网站采用反射,跨域返回时直接返回了域。若构造一个钓鱼页面诱导用户点击,由于用户点击时,源是信任的源,用户的apikey等被窃取。

img

防护方法:核心是正确设置Origin跨域白名单

1、代码层:Middleware统一处理

2、网关层:Nginx反代统一拦截处理

img

2.6 WebSocket

http 服务端的漏洞,在 WebSocket 上也可能存在,此次重点讨论 WebSocket 架构的一些问题。

img

1、WSS 和 WS:WSS (WebSockets over SSL/TLS),提供加密信道。杜绝掉一些中间人攻击。

2、数据校验:SQL/XSS/RCE 等漏洞仍然可能存在

3、CSWSH:Cross-Site WebSocket Hijacking,即在使用cookie作为认证方式时候,如果 WebSocket 服务端没有校验好请求来源(Origin),将导致 WebSocket 会话劫持。

CSWSH 防护手段:

1、Cookie鉴权:限制请求的Origin。

2、ticket/token鉴权:http服务提供接口,用于获取临时的身份凭证,并传递到WebSocket的初始化流程中

3.总结与思考

对于本人日常的服务端功能开发的启示:首先应深入了解所使用的框架、组件的原理,避免会引起sql注入的操作,严格区分静态模板与动态数据;二是要应对客户端发来的请求进行拦截,对其中的参数、文件等进行类型校验,处理不合规的参数字符;最后要做好权限控制,限制不同用户、不同源能够访问的内容。