前端知识补全
前端知识
- 接下来的内容会是我 面试 / 遇到 不会的点,或者是掌握得不清楚的点,我会尽可能将整个流程写明白,让我自己能跑通整个流程。
浏览器的同源策略?
What
- 当我们写好一个后端程序和前端程序的时候,前端向后端发送请求,提示CORS未通过,这通常是浏览器的同源策略导致的。
- 同源策略是浏览器对跨源读写的限制,例子:js不能读另一个源的响应内容。
- 链路:浏览器先执行同源策略 – 如果跨源,则需要带上CORS响应头显式访问 – 否则浏览器拦截
同源策略是拦截策略,而CORS是服务器给浏览器的许可证明
Why
- 这是为了防止Web里的跨源攻击,运行在某个 origin 下的脚本,不能读取其他 origin 的存储(localStorage/cookie/DOM)和响应内容;哪怕这些请求是用户本人在同一个浏览器里触发的。
How
- 服务端通过 CORS 配置决定向哪些 Origin 返回允许头;若未允许,浏览器会拦截前端 JS 读取响应(即使请求到达并拿到 200)。
- 校验三大部分:协议、主机名、端口
1 | public CorsFilter corsFilter() { |
XSS攻击?
What
- XSS攻击是用户将一段脚本(js)代码伪装成评论插入到系统里,当别人展开评论的时候,这段脚本会在网站里执行(因为当你展开评论的时候,浏览器把用户输入当 HTML 解析,前端可能会将评论使用innerHTML插入进到页面里,脚本被执行)
- 用户可能会看到奇奇怪怪的弹窗或者跳转到别的页面
- 账号被莫名改资料
- 如果你是权限比较高的用户,执行了恶意脚本,很可能就会让系统崩溃。
How to prevent
- 核心原则:永远不要把用户的输入当成HTML渲染
- React默认渲染字符串是转义的,{content}
- 坑:如果为了支持富文本(图片,代码,换行)使用了dangerouslySetInnerHTML,这样就会插入脚本。
- 解决方法:
- 输出编码要默认转义,用纯文本来渲染,不允许用html
- 白名单清洗:如果必须要富文本,过滤掉事件脚本,事件属性,危险的url结构
- token尽量不要放在localstorage里,可以放在HttpOnly cookie,这样js读不到cookie
- 设置SameSite,有三种模式,strict,lax以及none,分别控制跨站是否自动带上cookie
- 解决markdown富文本的XSS攻击策略
- 设置白名单,只允许我们可以的标签,比如p,a,strong,code等,对属性也要白名单,禁止所有的事件属性,比如on*
- 禁止inline script
- 代码块永远escape(转义)后放进code和pre里展示
JWT更安全的登录?双Token
What
- 我发现了原来的逻辑是改Localstorage就可以让前端渲染出管理员的界面,这样不行
- 于是引入了JWT的accessToken以及refreshToken
- accessToken一般时间短,15-30分钟,存放在React的内存里,一刷新就没有
- refreshToken时间在7-30天,存放在httponly的cookie里
- 此外这个refreshToken还存放在了redis里,使用版本号控制,让非法用户强制下线
How
登录功能
- 用户首次登陆的时候后端校验账户和密码是否合法,如果合法就签发两个token
- access token 过期 → 前端请求业务接口返回 401
- 前端调用 /api/v1/auth/refresh(不带 refresh token,浏览器会自动附带 HttpOnly Cookie)
- 后端从 Cookie 里拿 refresh token,去 Redis 校验是否存在/是否有效
- 校验通过 → 生成新 access token(和新的 refresh token),并在 Redis 里更新
- 返回新的 access token 给前端,继续请求
来回时间就是一个rtt
踢人功能
- 在redis里添加tokenVersion,因为我们登陆的时候用户还是有当前的accessToken,所以他还能存活这么久
- 加一个
user:tokenVersion:<uid>在redis里,签发的时候把ver写进JWT, - 踢人就增加版本号,这样让他的所有旧accessToken失效。原因是我们的在redis里的逻辑是
user:tokenVersion:<uid> = N,拦截器校验时比较Redis ver,如果不一致就401
- 加一个
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Explainfuture's Blog!
