常见前端安全总结 - XSS/CSRF/cookie/密码/HTTP传输/点击劫持
XSS
XSS定义:
- Cross site
- 本网站运行了来自其他网站的代码
- 数据变成了程序
XSS实例:
页面上输出query参数 页面上显示搜索框脚本 引入外部js资源 富文本 - 写日志 - 富文本 - 塞入的 - 加入scrpit 在线商城 - 订单信息input消息的填写 - 订单信息流入后台 - 获取后台的管理员信息和后台地址
XSS危害:
- 获取页面数据
- 获取cookie document.cookie
- 劫持前端逻辑
- 发送请求
XSS攻击分类:
XSS攻击点:包含用户输入行为
1.HTML节点内容
2.HTML属性
红框内为输入内容,导致属性标签闭合 添加了新的属性
3.javascript代码 - 强制标签闭合 - 搜索
4.富文本:富文本自带HTML
防御方法
1.浏览器自带 X-XSS-Protection
取值: 0关闭 1默认(开启) 1后面带参数 - 拦截后自动发送到该网址上 限制:只拦截反射类型注入 - 只对HTML属性和节点内容有用
demo(koa)
2.HTML节点内容/属性 - 转义成HTML实体
不被浏览器解析正常显示 < > 内容 “ ‘ 是属性
3.javascript代码
JSON.stringfy - 所有的单引号/双引号都会被转义
4.富文本
黑名单 - 正则替换 - 因为变形有很多,只能阻挡一部分 白名单 - 在白名单的HTML允许写入 - 实现复杂 - 把html解析成树状结构 - 依次分析过滤每个节点的name,attr,过滤掉不在白名单内的属性和tag 使用npm包 - xss自动实现 https://www.npmjs.com/package/xss
5.csp - http的头
content security policy 内容安全策略,用于指定哪些内容可执行
类型
Child-src 页面子内容 iframe Connect-src ajax Default-src fallback 所有的内容 Font-src Frame-src Img-src Manifest-src webapp Media-src audio/video Object-src 插件 Script-src Style-src Worker-src serviceWorker
配置选项 - 那些可信任那些不可信任
<host-source> 主机域名 <scheme-source> 协议 Self 同域 - 引入的资源 Unsafe-inline 直接插入页面的内容 Unsafe-eval none 不信任任何内容 Nonce-<base64-value> 指定一次性凭证 凭证匹配时可执行 <hash-source> Stric-dynamic 引入的后续网址是否
demo
没有指定的全部不信任,只信任同源的引入文件,对于直接插入的不信任
CSRF
CSRF定义
cross site request forgy 跨站请求伪造 Cross-site: 其他网站对本网站进行的影响,在用户不知情的额情况下向目标网站发送请求 打开连接就可能对其他网站进行操作 post请求 - 第三方站点攻击时 - 需要构建表单
<body> hello,这里什么也没有。 <script> document.write(` <form name="commentForm" target="csrf" method="post" action="http://localhost:1521/post/addComment"> <input name="postId" type="hidden" value="1"> <textarea name="content">来自CSRF!</textarea> </form>` ); var iframe = document.createElement('iframe'); iframe.name = 'csrf'; iframe.style.display = 'none'; document.body.appendChild(iframe); setTimeout(function(){ document.querySelector('[name=commentForm]').submit(); },1000); </script> </body>
Form在提交时会刷新 - 但如果指向一个iframe,则页面刷新会发生在iframe中
get会更容易,而且可以是一张图片等其他信息
csrf危害
- 更容易传播-把这种连接分享到社交网络中
- 利用用户登录态
- 用户不知情
- 完成业务请求
demo
qq音乐分享到qq空间,点击链接又可以发送
csrf攻击原理
s1:用户登录A网站
s2:A网站确认身份
s3:B网站页面向A网站发起请求(带A网站身份)
csrf解决思考
B网站向A网站请求,带A网站Cookies
不访问A网站前端
referer为B网站
csrf解决方法
1.禁止第三方网站带Cooike
- same-site属性[strict/Lax] Strict - 任何请求都不能带上 Lax - ajax/form不允许,链接可以 对于匿名无效 只对chrome/oprea支持
2.不经过A的前端页面
1.图像验证码 - ccap 必须经过A页面,去页面上拿到验证码,且用户必须输入 2.页面生成随机token - 攻击者必须经由前端页面才能拿到我们的页面 校验请求中的token和用户cookie中的token Token都可以拿到,是否有意义? ajax提交 - 吧token信息不让用户输入,而是放在页面的meta标签中来获取 WT:如果我打开了很多个页面,每打开一个页面就新生成一个token,导致只有最后的那个可以被提交,因为cookie中的被覆盖,怎么解决?
3.referer为B网站
referer http请求头, 请求来自于那里 验证请求referer 只允许本网站 - 不能直接indexOf域名,不严谨
Cookie
cookie特点
- 前端数据存储,可读写
- 后端通过Http头设置,请求时通过http头传给后端
- 遵守同源策略
cookie一旦设置,同源下的请求头上,都会带上cookie,只要是请求,就算是对css等静态资源的 请求
login接口的响应中可以看到设置cookie
cookie操作
前端操作:
Document.cookie - 获取 Document.cookie = ‘key=value’ 不是覆盖是追加?cookie特性 删除cookie - 设置cookie过期
cookie属性:
路劲:对网站不同层级设置不同的cookie 域名: 有效期:session(会话内有效) Http-only: 只允许请求,请求的发送和接受,js不能使用cookie,js中看不到 Secure: 只允许在https使用cookie Same-site:
cookie作用
存储个性化设置 存储未登录时用户唯一标识 存储已登录用户的凭证 存储其他业务数据
cookie登录用户凭证
存储个性化设置 存储未登录时用户唯一标识 存储已登录用户的凭证 存储其他业务数据
cookie加密demo
用户ID - 可以使用document.cookie随意更改 - 安全隐患 用户ID+签名 - crypto 篡改该用户名时,你永远不知道他的签名值是是多少
设置签名防止,篡改用户id 用户id,标识用户信息
校验签名:
sessionId - 服务器根据这个区寻找用户信息,再去验证你的身份 实现: 生成sessionId 缺点:服务重启会丢失 session持久化:文件、数据库、缓存(redis)
登录成功设置sessionID
评论验证获取userId
cookie与xss
- xss可能偷取cookies
- http-only的cookies不会被偷
cookie与xsrf
cookie存在浏览器端,当发送请求时,自动寻找该域下没有过期的cookie
- csrf利用了用户cookies
- 攻击站点无法读写cookies
- 最好能阻止第三方使用cookies
cookie安全策略
- 签名防篡改
- 私有变换(加密)
- http-only(防止XSS)
- secure
- same-site
cookie加密、解密demo
前端点击劫持
特征:
用户操作 用户不知情 点点点的游戏 - 打开摄像头
防御
javascript防御
直接页面和内嵌iframe页面的区别:top window不相等
反击:
Html5 iframe新属性 - shadow:禁止脚本运行,只允许表单提交
X-Frame-Options ie8+
请求头属性 DENY - 禁止内嵌 SAME-ORIGIN - 同一个网站 ALLOW-FROM - 只允许指定网站![clipboard.png](/img/bVbpTkt)
其他手段 - 验证码 - 辅助手段
HTTP传输安全
链路层?
http协议 请求明文发布 无加密
链路层有很多节点 - 传输过程中 - 转发这些流量数据 - 请求数据对这些节点都是公开透明的
Traceroute www.xingshulin.com
HTTP劫持和篡改
e.g.: 运营商劫持 - 校园网登录/提示续费网页 网站被塞广告 局域网劫持 支付宝网页 - 局域网流量走自己的机器,设置了一个网关,劫持了请求 公共wifi - 所有的流量 都经过这个 公共网络
解决:
改用https - TSL(SSL) 加密 将明文转为 密文 传输
但是存在还是存在伪造,劫持
解决:
发布证书 - CA 信任CA列表在 钥匙串访问 - 系统根证书 12306 security
保证这几个节点的安全:
证书无法伪造 证书不会被偷走,私钥不会被泄露 域名管理权不泄露 - CA在给该域名发布证书时,需要对域名的管理权进行验证 CA坚守原则 - CA不验证域名的话,不给发证书
部署
服务器申请证书: Ca 访问指定地址要求你给出指定的返回 访问一个域名 - 给出一个给定的值 模拟:https://www.sslforfree.com/
得到的CA:
把前两个合并
在一个web站点配置一个https的项目
1.服务器下新建项目目录 2.写入nignx配置文件
3.通过工具自动申请证书到服务器
自动脚本获取证书
curl https://get.acme.sh | sh
方法是:写入cert要求的内容
得到
4.把得到的证书放入配置文件
密码安全
泄露渠道
- 数据库被偷
- 服务器被入侵
- 通讯被窃听
- 内部人员泄露数据
- 其他网站(撞库)
密码存储
- 严禁明文存储(防泄露)
- 单向变换(防泄漏)
- 变换复杂度要求(防猜解)
- 密码复杂度要求(防猜解)
- 加盐(防猜解)
哈希算法 - 32字符串/提取/信息摘要算法
- 明文 - 密文 一一对应
- 雪崩效应
- 密文 - 明文 无法反推
- 密文固定长度
- 常见哈希算法:md5 sha1 sha256
单向变换彩虹表
加盐+增加用户的密码复杂度
变换次数越多越安全 - 密码加密解密只存在登录时 加密成本几乎不变(生成密码时速度慢一些) 彩虹表失效()
密码传输的安全性
密码加密 - 服务端实现
https传输
频率限制 - 避免猜出密码 - 一分钟输入10次 前端加密 - 意义有限 - http传输时,仍可以拿到 - 意义:防止拿到明文密码登陆其他相关网站
Npm install js-md5
密码加密 - 服务端实现
旧用户没有salt,升级 if (!user.salt) { var salt = password.getSalt(); var newPassword = password.encryptPassword(salt, user.password) await query(`update user set password = '${newPassword}', salt = '${salt} where id = ${user.id}'`) user.salt = salt user.password = newPassword } var encryptPassword = password.encryptPassword(user.salt,user.password) if (encryptPassword !== user.password) { throw new Error('密码不正确') }
上传问题
定义
公司使用的基本都是node服务,不过度叙述了哈哈哈~
上传文件 再次访问上传的文件 上传的文件被当做程序解析