手绘 10 张图,把 CSRF 跨域攻击、JWT 跨域认证说得明明白白的

从智能家居到智慧城市:AI Agent Harness Engineering 作为统一控制中枢 我们可以把每个独立的智能系统看作一根带有独立功能的电线:智能家居Agent是负责家庭设备控制的电线,社区Agent是负责社区管理的电线,城市交通Agent是负责交通调度的电线,而AHE就是把这些分散的电线整合起来的「智能线束」:它不仅负责把不同接口、不同协议、不同层级的Agent连接起来,还提供统一的编排、调度、协同、观测能力,实现全局效用最大化的智能决策。 阅读详情

点击上方“AI派”,选择“加为星标”

第一时间关注Python技术干货!

本文是 【网络知识扫盲】专栏的第四篇。

这篇文章本应该是属于 HTTP 里的一部分内容,但是我看内容也挺多的,就单独划分一篇文章来讲下。

1. 什么是跨域请求

要明白什么叫跨域请求,首先得知道什么叫域。

域,是指由 协议 + 域名 + 端口号 组成的一个虚拟概念。

如果两个域的协议、域名、端口号都一样,就称他们为同域,但是只要有其中一个不一样,就不是同域。

那么 跨域请求 又是什么意思呢?

简单来说,就是在一个域内请求了另一个域的资源,由于域不一致,会有安全隐患。

2. 跨域请求的安全隐患

有一个词,叫 CSRF (Cross-site request forgery)攻击,中文名是 跨站请求伪造。

简单来说呢,就是攻击者盗用了你的身份,以你的名义发送恶意请求,它能做的坏事有很多,比如以你的名义发邮件,发消息,购物,盗取帐号等。

CSRF 的实际工作原理是怎样的?

比如现在有两个网站,A 网站是真实受信息的网站,而 B网站是危险网站。

当你登陆 A 网站后,浏览器会存储 A 网站服务器给你生成的 sessionid 存入 cookie,有了这个 cookie ,就拥有了你的帐号权限,以后请求资料,就不用再次登陆啦。

对于真实用户来说,是便利,可对于攻击者来说,却是可乘之机。

Cookie + Session 方法

他们可以使用各种社工学引导你点击他们的链接/网站,然后利用你的浏览器上存储的 cookie ,然后在自己的 网站B 发起对 网站A 的请求,获取一些隐私信息,做一些侵害用户权益的事情。这便是一个完整的 CSRF 攻击。

3. 跨域请求的安全防御

完成一次完整的 CSRF 攻击,只要两个步骤:

  1. 登录受信任网站A,并本地已经存储了 Cookie

  2. 在不登出A的情况下,访问危险网站B,网站 B 诱导你发 A 发请求。

很多浏览器用户对于网络安全是无意识的,因此我们不能指望通过规范用户行为来避免CSRF攻击。

那如何从技术手段规避一定的 CSRF 攻击的风险呢?

  1. 利用浏览器的同源策略:最基础的安全策略

  2. 对请求的来源进行验证:Referer Check

  3. 使用验证码强制使用户进行交互确认,保证请求是用户发起

  4. CSRF Token,注意不要使用 cookie 来存储token

  5. JSON Web Token

以上是我知道的历史上用来抵御 CSRF 攻击的方法

  • 有的虽然实现简单,但是不够安全

  • 有的虽然安全,但是用户体验不好

  • 有的虽然安全,用户体验好,但是有缺点

具体应该选哪一种呢,不妨继续往下看。

3.1 同源策略

浏览器上有一个同源策略(SOP,全称 Same origin policy),它会在一定程度上禁止这种跨域请求的发生。

但同源策略是最基本的安全策略,对于低级的 CSRF 攻击 ,它是很有效果的。

可以说 Web 是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。

同源策略在提升了 Web前端的安全性的同时,也牺牲了Web拓展上的灵活性。

设想若把html、js、css、flash,image等文件全部布置在一台服务器上,小网站这样凑活还行,大中网站如果这样做服务器根本受不了的,因此同源策略,就像是双刃剑。不过这些都是有解的。

3.2 Referer Check

在 HTTP 协议中,有一个字段叫做 Referer,它记录了HTTP 请求的来源地址。

当发生 CSRF 攻击时,这个来源地址,会变成危险网站 B,因此只要在服务端校验这个 Referer 是不是和自己同一个域就可以判断这个请求是跨站请求。

Referer Check 图解

但这种方法,也是有局限性的,在一些非主流的浏览器,或者使用了那些非常古老的浏览器版本,这个  Referer 字段,是有可能会被篡改的。

退一步讲,假设你使用了最安全的最新版本的浏览器,这个值无法被篡改,依旧还是有安全隐患。

因为有些用户出于某些隐私考虑,会在浏览器设置关闭这个 Referer 字段,也有的网站会使用一些技术手段使用请求不携带 Referer 字段。

因此,当你要使用 Referer Check 来做为 防御 CSRF 攻击的主要手段时,请确保你的用户群体使用的一定是最安全的最新版本的浏览器,并且默认用户不会手动关闭 Referer 。

3.3 加验证码

验证码,强制用户必须与应用进行交互,才能完成最终请求。

其实加验证码,是能很好遏制 CSRF 攻击,但是网站总不能给所有的操作都加上验证码吧,那样的话,用户估计都跑光光了,因此为了保证用户体验,验证码只能作为一种辅助手段,不能作为主要解决方案。

3.4 CSRF Token

CSRF 攻击之所以能够成功,是因为黑客可以完全伪造用户的请求,该请求中所有的用户验证信息都是存在于 cookie 中,因此黑客可以在不知道这些验证信息的情况下,直接利用用户自己的 cookie 来通过安全验证。

所以要抵御 CSRF,关键在于要在请求中放入黑客所不能伪造的信息,并且该信息不存在于 cookie 之中(不然黑客又能拿到了)。

业界普遍的防御方案是使用 CSRF Token

使用 CSRF Token 根据token验证方式的不同,也可以分为两种:

第一种:如图所示

  1. 当用户请求一个更新用户名的页面时,由服务端生成一个随机数 Token,然后放入HTML表单中传给浏览器,并且存入 session 中。

  2. 当用户提交表单请求时,表单数据会带上这个 Token 发送给服务端 ;

  3. 服务端收到表单请求后,会从表单数据里取出 Token,然后和 session 里的 token 进行对比,如果是一样的,就是合法的用户请求,将新的用户名存入数据库,如果不一样,那就是非法的请求,应当拒绝。

第二种:

  1. 当用户请求一个更新用户名的页面时,由服务端生成一个随机数 Token,然后放入HTML表单中,并且会把这个 Token 放在 cookie 里发给浏览器。

  2. 当用户提交表单请求时,表单数据会带上这个 Token 发送给服务端,并且带上携带 token 的 cookie ;

  3. 服务端收到表单请求后,会从表单数据里取出 Token,与 cookie 里的 token 进行对比,如果是一样的,就是合法的用户请求,将新的用户名存入数据库,如果不一样,那就是非法的请求,应当拒绝。

3.5 新增 Header

使用上面的 CSRF Token 已经可以避免 CSRF 攻击,但是它却有可能又引入了另一个问题。

若 CSRF Token 没有使用 cookie,就必须要将 Token 存储在服务端的 Session 中,这样就会面临几个问题

  1. 服务端每生成一个 Token,都会存放入 session 中,而随着用户请求的增多,服务端的开销会明显增大。

  2. 如果网站有多个子域,分别对应不同的服务器,比如 taobao.com 后台是服务器 a,zhibo.baotao.com 后台是 服务器b, 不同子域要想使用同一个 Token,就要求所有的服务器要能共享这个 Token。一般要有一个中心节点(且应是一个集群)来存储这个Token,这样看下来,架构就变得更加复杂了。

想要解决这些问题,可以使用我们接下来要讲的 JWT(全称:JSON Web Token)

使用了 JWT 后,有了哪些变化呢

  1. 服务器只负责生成 Token和校验Token,而不再存储Token

  2. 将服务器的压力分摊给了所有的客户端。

  3. 服务端的 鉴权不使用 cookie ,而是由新增的 Header 字段:Authorization  里的 JWT 。

JWT 是本篇文章重要知识点之一,下面我会详细说说关于 JWT 的内容。

4. JWT 的工作原理及目的

为了让你直观感受 JWT 的工作原理,我画了下面这张图

JWT 工作图解
  1. 用户以 Web表单 的形式,将自己的用户名和密码 POST 到后端的接口。

  2. 后端核对用户名和密码成功后,会计算生成JWT Payload 字符串(具体计算方法,后续会讲),然后返回 response 给浏览器。

  3. 浏览器收到 JWT 后,将其保存在 cookie 里或者 localStorage 或者 sessionStorage 里(具体如何选,后面会说)。

  4. 后续在该域上发出的请求,都会将 JWT放入HTTP Header 中的 Authorization 字段。

  5. 后端收到新请求后,会使用密钥验证 JWT 签名。

  6. 验证通过后后端使用 JWT 中包含的用户信息进行其他相关操作,返回相应结果。


JSON Web Token (JWT) — The right way of implementing, with Node.js

JWT 的诞生并不是解决 CSRF 跨域攻击,而是解决跨域认证的难题。

举例来说,A 网站和 B 网站是同一家公司的关联服务。现在要求,用户只要在其中一个网站登录,再访问另一个网站就会自动登录,这应该如何实现呢?

一种解决方案是 session 数据持久化,写入数据库或别的持久层。各种服务收到请求后,都向持久层请求数据。这种方案的优点是架构清晰,缺点是工程量比较大。另外,持久层万一挂了,就会单点失败。

另一种方案是服务器索性不保存 session 数据了,所有数据都保存在客户端,每次请求都发回服务器。

JWT 就是这种方案的一个优秀代表。

5. JWT 如何生成?

JWT 其实就是一个字符串,比如下面这样

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

仔细观察,会发现它里面有三个 . ,以 . 为分界,可以将 JWT 分为三部分。

  1. 第一部分:头部(Header)

  2. 第二部分:载荷(Payload)

  3. 第三部分:签名(Signature)

5.1 头部(Header)

JWT 的头部承载两部分信息:

  • 声明类型:这里是 JWT

  • 声明加密的算法:通常直接使用 HMAC SHA256

完整的头部就像下面这样的JSON:

{
  "typ": "JWT",
  "alg": "HS256"
}

然后将头部进行 Base64URL 算法编码转换,构成了第一部分

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

5.2 载荷(Payload)

载荷,同样也是个 JSON 对象,它是存放有效信息的地方,但不建议存放密码等敏感信息。

JWT 规定了7个官方字段,供选用:

  • iss (issuer):签发人

  • exp (expiration time):过期时间

  • sub (subject):主题

  • aud (audience):受众

  • nbf (Not Before):生效时间

  • iat (Issued At):签发时间

  • jti (JWT ID):编号

除了官方字段,你还可以在这个部分定义私有字段,下面就是一个例子。

注意,JWT 默认是不加密的,任何人都可以读到,所以不要把秘密信息放在这个部分。

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

然后将其进行 Base64URL 算法转换,得到 JWT 的第二部分。

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

5.3 签名(Signature)

Signature 部分是对前两部分的签名,防止数据篡改。

首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.)分隔,就可以返回给用户。

6. 如何手动生成 JWT?

如果你想手动生成一个 JWT 用于测试,有两种方法

第一种:使用 https://jwt.io/ 这个网站 。

我使用前面的 header 和 payload,然后使用 secret 密钥:Python

最后生成的 JWT 结果如下

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.3wGDum3_A8tAt1bdal5CpYbIUlpHfPQxs96Ijx883kI

第二种:使用 Python 代码生成

首先安装一下 pyjwt 这个库

$ pip install pyjwt

然后就可以在代码中使用它

import jwt
import datetime
import uuid

salt = 'minggezuishuai'

# 构造header , 这里不写默认的也是
headers = {
    'typ': 'JWT',
    'alg': 'HS256'
}

# 构造payload
payload = {
    'user_id': str(uuid.uuid4()),  # 自定义用户ID
    'username': "wangbm",  # 自定义用户名
    'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=5)  # 超时时间,取现在时间,五分钟后token失效
}
token = jwt.encode(payload=payload, key=salt, algorithm="HS256", headers=headers).decode('utf-8')

# token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiODg4ZjIwZDktMDdlZC00MWJkLWIzMjktMTdjNmYwNThhMTRlIiwidXNlcm5hbWUiOiJ3YW5nYm0iLCJleHAiOjE1OTQ0MzQzMjZ9.kkEMhSx732lO6HWWNPNVQDHR9WuCEVxKgNol-LTbCP8

如果你只是测试使用,完全不用写那么多代码,用命令行即可

$ pyjwt --key="minggezuishuai" encode user_id=888f20d9-07ed-41bd-b329-17c6f058a14e username=wangbm exp=+120
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiODg4ZjIwZDktMDdlZC00MWJkLWIzMjktMTdjNmYwNThhMTRlIiwidXNlcm5hbWUiOiJ3YW5nYm0iLCJleHAiOjE1OTQ0MzQ4NTl9.A792th12kY1YnBWyVgbr5l6OQ5emRiETIjsnmIl4Ji8

7. Base64URL 算法

前面提到,Header 和 Payload 串型化的算法是 Base64URL。这个算法跟 Base64 算法基本类似,但有一些小的不同。

JWT 作为一个令牌(token),有些场合可能会放到 URL(比如 api.example.com/?token=xxx)。Base64 有三个字符+、/和=,在 URL 里面有特殊含义,所以要被替换掉:=被省略、+替换成-,/替换成_ 。这就是 Base64URL 算法。

8. JWT 如何保存?

关于浏览器应该将 JWT 保存在哪?这个问题,其实也困扰了我很久。

如果使用搜索引擎去查,我相信你也一定会被他们绕晕。

比如在这篇帖子(When and how to use it )里,作者的观点是,不应该保存在 localstorage  和 session storage,因为这样,第三方的脚本就能直接获取到。

作者推荐的做法是,将 JWT 保存在 cookie 里,并设置 HttpOnly。

再比如这一篇帖子(JWT(JSON Web Token) : Implementation with Node)提到了要把 JWT 保存到 local-storage。

因此,我决定不再看网络上关于 『应将 JWT 保存的哪?』的文章。而是自己思考,以下是我个人观点,不代表一定正确,仅供参考 。

JWT 的保存位置,可以分为如下四种

  1. 保存在 localStorage

  2. 保存在 sessionStorage

  3. 保存在 cookie

  4. 保存在 cookie 并设置 HttpOnly

第一种和第二种其实可以归为一类,这一类有个特点,就是该域内的 js 脚本都可以读取,这种情况下 JWT 通过 js 脚本放入 Header 里的 Authorization 字段,会存在 XSS 攻击风险。

第三种,与第四种相比,区别在于 cookie 有没有标记 HttpOnly,没有标记 HttpOnly 的 cookie ,客户端可以将 JWT 通过 js 脚本放入 Header 里的 Authorization 字段。这么看好像同时存在CSRF 攻击风险和 XSS 攻击风险,实则不然,我们虽然将 JWT 存储在 cookie 里,但是我们的服务端并没有利用 cookie 里的 JWT 直接去鉴权,而是通过 header 里的 Authorization 去鉴权,因此这种方法只有 XSS 攻击风险,而没有 CSRF 攻击风险。

而第四种,加了 HttpOnly 标记,意味着这个 cookie 无法通过js脚本进行读取和修改,杜绝了 XSS 攻击的发生。与此同时,网站自身的 js 脚本也无法利用 cookie 设置 header 的Authorization 字段,因此只能通过 cookie 里的 JWT 去鉴权,所以不可避免还是存在 CSRF 攻击风险。

如此看来,好像不管哪一种都有弊端,没有一种完美的解决方案。

是的,事实也确实如此。

所以我的观点是,开发人员应当根据实际情况来选择 JWT 的存储位置。

  • 当访问量/业务量不是很大时,可以使用 CSRF Token 来防止 CSRF 攻击

  • 而如果访问量/业务量对服务器造成很大压力,或觉得服务器共享 token 对架构要求太高了,那就抛弃CSRF Token 的方式,而改用 JWT。选择了 JWT ,就面临着要将 JWT 存储在哪的问题。

  • 若选择了 JWT ,那么请不要使用 cookie HttpCookie 来存储它,因为使用它还是会有 CSRF 攻击风险。

  • 那另外三种如何选择呢?这三种无论使用哪种,都不可避免有 XSS 攻击风险。我的思路是,XSS 攻击通过其他的手段来规避,这里使用JWT 只有 防御 CSRF 攻击与服务器性能的优化,这两个目标。

  • 那我剩下的三种,我建议是使用 cookie 存储,但不使用 cookie 来鉴权。服务器鉴权还是通过请求里的 Authorization 字段(通过js写入 Header 的)。

当然,如果你觉得你通过 Referer Check 、加验证码 等其他手段,已经可以保证不受 CSRF 攻击的威胁,此时你使用 JWT ,就可以选择使用 JWT + cookie HttpOnly,扼杀 XSS 攻击的可能。

9. JWT 如何发送?

通过上面第七节的描述,其实我也讲到了 JWT 根据不同场景可以选择两种发送方式

  • 第一种:将 JWT 放在 Header 里的 Authorization 字段,并使用 Bearer标注

'Authorization': 'Bearer ' + ${token}
  • 第二种:把 JWT 放入 cookie ,发送给服务端,虽然发送。但是不使用它来鉴权。

10. JWT 如何校验?

后端收到请求后,从 Header 中取出 Authorization 里的 JWT ,使用之前的签名算法对 header 和 payload 再次计算生成新的签名,并与 JWT 里的签名进行对比,如果一样,说明校验通过,是个合法的 Token。

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

验证是个合法的 Token 后,还要检查这个 Token 是否过期,在 JWT 里的 payload 中,有 Token 的过期时间,可以通过它来检查  Token 是否可以用?

payload 里同时还有用户的相关信息,有了这些信息后,后端就可以知道这是哪个用户的请求了,到这里一切都验证通过,就可以执行相关的业务逻辑了。

前面我使用了 pyjwt 这个来生成 JWT ,事实上,这个库也可以用来验证 token。

使用 jwt 的 decode 会先验签再解码取得 payload 的信息。

>>> import jwt
>>> token="eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiODg4ZjIwZDktMDdlZC00MWJkLWIzMjktMTdjNmYwNThhMTRlIiwidXNlcm5hbWUiOiJ3YW5nYm0iLCJleHAiOjE1OTQ0MzQzMjZ9.kkEMhSx732lO6HWWNPNVQDHR9WuCEVxKgNol-LTbCP8"
>>> jwt.decode(token, 'minggezuishuai', algorithms=['HS256'])
{'user_id': '888f20d9-07ed-41bd-b329-17c6f058a14e', 'username': 'wangbm', 'exp': 1594434326}
>>>

验签同样也可以使用命令行

$ pyjwt --key="minggezuishuai" decode eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiODg4ZjIwZDktMDdlZC00MWJkLWIzMjktMTdjNmYwNThhMTRlIiwidXNlcm5hbWUiOiJ3YW5nYm0iLCJleHAiOjE1OTQ0MzQ4NTl9.A792th12kY1YnBWyVgbr5l6OQ5emRiETIjsnmIl4Ji8
{"user_id": "888f20d9-07ed-41bd-b329-17c6f058a14e", "username": "wangbm", "exp": 1594434859}

如果不想验证签名及有效期,而只是想取下payload,只需加个--no-verify 参数即可

$ pyjwt --key="minggezuishuai" decode --no-verify {token}

更的详细使用方法,可以执行 pyjwt --help 学习或者前往官方文档:https://pyjwt.readthedocs.io/en/latest/index.html

11. JWT 的最佳搭配

在真正的业务中,是有可能使用 payload 来存放一些用户的敏感信息的,由于 payload 是采用 Base64URL 转换而成,它是可逆的,因此当你在 payload 存放敏感信息时,需要保证 JWT 的安全性,不能让其暴露在 『阳光』下。

为此,JWT 最好与 HTTPS 配合使用,利用 HTTPS 的非对称加密来保证 JWT 的安全。

具体是如何保障的呢?

HTTPS 是基于 SSL/TLS 的非对称加密算法工作的。

在非对称加密算法的规则下,服务器会拥有一个叫做『私钥』的东西,它是私有的,除了服务器之外,不能再有第二个人知道它。

而相对的,所有的客户端(浏览器)同时也会有一个叫做『公钥』的东西,它是对所有人公开的,任何人都可以拥有它。它与『私钥』合称为一个密钥对。

公钥和私钥的规则是:

  • 公钥加密的东西,只有私钥能解。因此如果 JWT 的 payload 里有你的敏感信息,那也不要紧,只要把 JWT 用公钥(前提是这个公钥得是正确的,下面会说到)加密一下,那黑客就算拿到了这个密文,也无法解密,因为私钥只有服务器才有。

  • 私钥加密的东西,所有的公钥也都能解。因此服务器发给客户端的 JWT 的payload 尽量不要有敏感信息。

那么问题又来了,如果客户端拿到的公钥,是黑客伪造的,客户端拿着这个假公钥加密自己的敏感信息,然后发出去,黑客在拿到这个用自己伪造的公钥加密的数据,非常开心,因为这个公钥对应的私钥在自己手里,自己是可以解密得到里面的数据的。

因此如何保证服务器发给客户端(浏览器)的公钥是正确的呢?

答案是通过数字证书来保证。但是由于这个不是本文的重点,因此我将这块内容放在后面的文章详细解释。

12. 总结写在最后

最后,我总结一下,本文的要点:

  1. CSRF 攻击的产生,需要cookie 的『助攻』,否则无法完成。

  2. CRSF 是利用 cookie,而不是盗取 cookie,这点一定要明白。

  3. 但也并不是使用了 cookie 就会有 CSRF 风险,而应该说是用 cookie 去做鉴权才会有 CSRF 风险,参考 CSRF Token (把 token 存储在 cookie 的情况)和 JWT (把 token 存储在 cookie 的情况)。

  4. CSRF Token 和 JWT 虽然都可以做到防御 CSRF 攻击,但其实无论是哪个都无法同时做到防御 CSRF 和 XSS 攻击,在阻止了 CSRF 攻击后, 需要再通过其他手段来减少 XSS 攻击的可能性。

  5. JWT 就是一个由服务端按照一定的规则生成的字符串,

  6. JWT 的目的是为了做一个无状态的 session,避免去频繁查询 session,减少了对服务器产生的压力,简化后端架构模型。它的主要用途是解决跨域认证的问题,而解决 CSRF 跨域攻击只是它的附带功能。

  7. payload 是经过 base64URL 算法转换而成的字符串,是可逆的,因此尽量不要存放敏感数据,如若非要存放敏感数据,最好与 HTTPS 协议搭配使用,避免数据泄露。

  8. JWT 的保存位置与方式,没有绝对的方案,具体如何选择要视情况而定。




本文的内容到这里就结束了,非常感谢大家的阅读!如果写的内容对你有帮助,还希望你能帮忙转发扩散,同时若对本文有不一样的理解,欢迎留言一起交流。

文末福利

各位猿们,还在为记不住API发愁吗,哈哈哈,最近发现了国外大师整理了一份Python代码速查表和Pycharm快捷键sheet,火爆国外,这里分享给大家。

这个是一份Python代码速查表

下面的宝藏图片是2张(windows && Mac)高清的PyCharm快捷键一览图

怎样获取呢?可以添加我们的AI派团队的程序媛姐姐

一定要备注【高清图】哦

????????????????????

➕我们的程序媛小姐姐微信要记得备注【高清图】哦

来都来了,喜欢的话就请分享、点赞、在看三连再走吧~~~

UNet 改进(39):结合残差连接与CBAM注意力机制的unet模型 本文提出了一种改进的UNet架构,通过融合残差连接和CBAM注意力机制来增强医学图像分割性能。该网络保留UNet的U形结构,但将基础模块替换为ResidualBlock和CBAM的组合:残差块通过快捷连接解决梯度消失问题,CBAM模块结合通道和空间注意力机制突出重要特征。整体架构采用编码器-解码器设计,包含5个下采样和上采样阶段,通过跳跃连接融合多尺度特征。实验表明,这种改进显著提升了原始UNet的性能,特别适用于需要精细边界的医学图像分割任务。 阅读详情

相关推荐

Python自动化测试报告:飞书群机器人消息卡片实战

本文详细介绍了如何利用Python和飞书群机器人实现自动化测试报告的智能通知。通过构建可定制的消息卡片,将测试结果(如通过数、失败数)以清晰、美观的格式自动推送至团队群聊,并支持一键跳转查看详细报告,从而显著提升团队协作与问题响应效率。

k6l7m8n9的博客 811

js异步实例之跨域获取图片

文章目录前言问题描述解决问题获取图片异步渲染结语 前言 我们知道js中有关异步编程的知识有很多,比如以Promise,await/async等系列的异步语法,以及XMLHttpRequest,fetch系列的js异步请求API。这篇博客我将以一个实际的应用案例来究竟如何使用异步编程来解决问题。(这里我不对这些异步语法以及异步API的使用作讲解,如果有对其不了解的读者可自行去mdn官方文档进行查阅学习。) 问题描述 现在我需要使用js代码来获取网络上一跨域的图片资源,并且需要在指定的时机将其渲染到页面上。 图

Rookie 7090

SAP 凭证分割功能 - 概述&系统配置 - Chapter01/02

为何要进行凭证拆分(分割)?在启用凭证分割之前, 在财务凭证在过账时会自动带出默认的利润中心,这利 润中心一般是从其他对象派生出来的(比如从成本中心、WBS 或资产负债表科 目定义默认的利润中心等),但是某些情况下的财务过账是不会派生出利润中 心的,比如说应收或者应付。如果一笔销售凭证上有两个行项目,10 行对应的成品物料 A 的利润中心为 TPCA-100;公司项目Dr/Cr科目金额利润中心10001Dr应收账款20002Cr库存商品A1500TPCA-1003Cr。

weixin_46525734的博客 3973

SpringBoot-JWT基础知识、CSRF、JWT、SpringBoot如何使用JWT、登录拦截器

SpringBoot-JWT基础知识、CSRF、JWT、SpringBoot如何使用JWT、登录拦截器

m0_56161114的博客 769

openEuler在虚拟机的网络配置

ethernet0.virtualDev 可以配置成其他类型的虚拟网络适配器。常见的选项包括:vlance - 用于模拟 AMD PCnet32 LANCE 网络适配器,支持10Mbps。e1000 - 用于模拟 Intel E1000 千兆网络适配器,支持1Gbps。e1000e - 用于模拟更现代的 Intel E1000e 千兆网络适配器。vmxnet - 用于 VMware 的自定义网络适配器,性能更好但需要安装 VMware Tools。

FHY1221的博客 2933

Python与网络爬虫案例:电影评论抓取

接下来,我们就可以通过分析该页面中的HTML代码,来确定需要抓取的内容。在这段代码中,我们首先对每个评论div元素进行for循环,然后通过find方法获取class为'title'、'text'、'rating-other-user-rating'的元素,并将结果分别赋值给title、content和rating变量。在这段代码中,我们首先定义了目标网站的URL和headers信息,然后通过requests.get方法向目标网站发送了一个GET请求,并将返回的响应赋值给了response变量。

吃不胖. 1264

一文带你吃透 CSRF、Cookie、Session、Token 与 JWT 的底层逻辑

本文深入解析了Web开发中的核心安全机制。Cookie解决了HTTP无状态问题,Session则弥补了Cookie的安全缺陷,通过SessionID在服务端存储敏感数据。Token技术进一步优化了分布式场景下的身份验证,其无状态特性降低了服务器负担。文章还剖析了CSRF攻击原理,指出Token能有效防范此类攻击。最后介绍了JWT技术,它通过加密签名实现更安全的无状态验证。这些机制各具特点:Cookie/Session适合小型系统,Token适用于高并发场景,JWT则在跨域和微服务架构中表现优异。开发者需根据

大河之犬的博客 1874

华为OD机试真题 新系统 2026-07-22 Java&Go&C 实现【最小代价完成论文评审】

某校有 n 篇论文需要分配给教师评审。 每篇论文 i 可由 files[i] 对应的教师列表中任一教师评审。 每篇论文至少需要一名教师评审。 每位教师 t 不论被分配多少篇论文,其评审费用固定为 cost[t]。 请给出参与评审教师数量最少时的总费用。 如果存在多种方案满足教师数量最少,则选择总费用最小的方案。

MISAYAONE的博客 153

HTML页面跨域请求图片资源报错:Failed to load resource: the server responded with a status of 403 (Forbidden)

HTML页面跨域请求图片资源报错:Failed to load resource: the server responded with a status of 403 (Forbidden)

指尖流连敲击梦想,代码行行承载远方! 5369

DRV8311HRRWR直流无刷(BLDC)电机驱动原理图设计

DRV8311HRRWR集成三个MOSFET 半H桥,用于驱动三相无刷直流电机(BLDC),适用于5V、9V、12V或18V直流电源轨或1S至4S电池供电应用。内部集成三个具有集成电流感测功能的电流感测放大器(CSA),可感测BLDC电机的三相电流,从而实现FOC和电流控制系统设计方案。集成保护特性:VM 欠压锁定 (UVLO)、 电荷泵欠压 (CPUV)、过流保护 (OCP)、热警告和热关断 (OTW/OTSD)、故障条件指示引脚 (nFAULT)支持 1.8V、3.3V 和 5V 逻辑输入。

zhusl6688的博客 1229

AI 实战篇 |基于 AI开放平台实现 人脸识别对比 功能,超详细教程【附带源码】

本篇文章来学习一下怎样使用 Unity实现简单地人脸识别 功能。 关于人脸识别,我们可以选择很多平台的SDK接入Unity来实现人脸识别的功能。

努力前行,总会成为自己心中的那道光 5万+

[Web 安全] 如何通过JWT防御CSRF

名字都是用来唬人的。 先解释两个名词,CSRF 和 JWT。 CSRF (Cross Site Request Forgery),它讲的是你在一个浏览器中打开了两个标签页,其中一个页面通过窃取另一个页面的 cookie 来发送伪造的请求,因为 cookie 是随着请求自动发送到服务端的。 JWT (JSON Web Token),通过某种...

weixin_34311757的博客 852

【批处理脚本】-0.1-如何运行批处理bat文件

如何运行批处理bat文件

「汽车电子助手」的博客 1586

手绘10张图,把CSRF跨域攻击、JWT跨域认证说得明明白白的

作者 |写代码的明哥来源|Python编程时光这篇文章本应该是属于 HTTP 里的一部分内容,但是我看内容也挺多的,就单独划分一篇文章来讲下。什么是跨域请求要明白什么叫跨域请求,首...

AI科技大本营 6146

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

前端安全(http)

CSRF (Cross-site request forgery)攻击,中文名是跨站请求伪造。引导你点击他们的网站, 然后用你的身份做坏事。会导致: 会话劫持, 钓鱼, 信息泄露 , 不会导致拒绝服务。受理重要请求, 要求客户端提供用户口令/动态密码/验证码。cross site script 跨站脚本攻击。window 跳转 和 a 标签跳转。

YogaMiller的博客 507

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

干货丨Pyecharts 绘制好看的交互式地图教程

“ 阅读本文大概需要 5 分钟。 ”1Pyecharts-Map首先要介绍的是 Pyecharts 中使用最多的 Map() 方法,我们生成全国范围的销售额分布图,如下当然我们也可以用来...

静觅 433

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

如何成为一个搜索达人?

“ 阅读本文大概需要 7 分钟。 ”今时今日,总有一些搜索达人,只要你一句话,他们就能以最快的速度找到高质量的信息。提升搜索能力 = 提升工作能力但是搜到的东西文不对题?如果你的工作和学...

静觅 1094

2020 年 7 月 Github 上最热门的 JavaScript 开源项目

“ 阅读本文大概需要 10分钟。 ”1vuehttps://github.com/vuejs/vue Star 16048Vue.js 是构建 Web 界面的 JavaScript 库...

静觅 395

我把7大跨域解决方法原理画成10张图

前言 大家好,我是鹏帅。用最通俗易懂的话讲最难的知识点是我的座右铭,基础是进阶的前提是我的初衷。 咱们做前端的,平时跟后端对接接口那是必须的事情,但是可能很多同学忽略了一个对接过程中可能会发生的问题——跨域,那跨域到底是啥呢?为什么会跨域呢?又怎么才能解决呢? 为什么跨域? 为什么会出现跨域问题呢?那就不得不讲浏览器的同源策略了,它规定了协议号-域名-端口号这三者必须都相同才符合同源策略 如有有一个不相同,就会出现跨域问题,不符合同源策略导致的后果有 1、Loca..

前端小白-Mr鹏帅 987

JWT详解

jwt详解

2302_76649176的博客 1185

跨站请求伪造CSRF引发的思考Cookie、Session、Token和JWT

目录 1.最重要的问题: CSRF攻击是怎样跨域拿到cookie的? 2.CSRF 跨站伪造请求 3.Cookie和Session 4.Cookie和Session的区别 5.什么是Token(重点) 仅仅用seesion+cookie存在的问题 【疑问?】token放在客户端哪里?客户端是怎么每次取到token的 6.JSON Web Token(JWT) Token和JWT: 1.最重要的问题: CSRF攻击是怎样跨域拿到cookie的? 【疑问?】浏览器对于 cookie

wdquan19851029的专栏 6263

JWT与XSS/CSRF攻击

https://www.jianshu.com/p/344947705c3d

方方园园的博客 686

JWT、seesion、cookie、csrf漏洞

JWT、seesion、cookie、csrf漏洞

lza20001103的博客 768

为什么JWT认证解决不了CSRF(跨站请求伪造)和XSS(跨站脚本攻击)问题

JWT是一种无状态认证机制,但它本身无法防御CSRF和XSS攻击。CSRF风险主要源自JWT存储在非HttpOnly Cookie时自动携带令牌的特性,需配合SameSite属性或CSRF Token进行防护。XSS风险则源于JWT存储在可被脚本访问的localStorage中,建议优先使用HttpOnly Cookie存储并配合CSP策略。JWT与传统Session相比,在CSRF防护方面无优势,且XSS风险更高。最佳实践包括:使用HttpOnly+Secure Cookie存储JWT、实施CSP策略、设

chen2017sheng的博客 1023

JWT基于Cookie的会话保持,并解决CSRF问题的方案

避免CSRF问题可以通过自定义Header方式的处理,所以我们可以在使用Cookie记录JWT的基础上,增加一个无实际意义并且唯一的sessionId,每个接口调用都使用自定义Header SID传递该值,在服务端使用过滤器或者拦截器验证SID的值是否和JWT中的值一致。使用JWT进行浏览器接口请求,在使用Cookie进行会话保持传递Token时,可能会存在 CSRF 漏洞问题,同时也要避免在产生XSS漏洞时泄漏Token问题,如下图在尽可能避免CSRF和保护Token方面设计了方案。

小单的博客专栏 849

一个关于image访问图片跨域的问题

通过 'img' 加载的图片,浏览器默认情况下会将其缓存起来。当我们从 JS 的代码中创建的 'img' 再去访问同一个图片时,浏览器就不会再发起新的请求,而是直接访问缓存的图片。但是由于 JS 中的 'img' 设置了 crossorigin,也就意味着它将要以 CORS 的方式请求,但缓存中的图片显然不是的,所以浏览器直接就拒绝了。连网络请求都没有发起。

weixin_42333548的博客 9653
上一篇: 数据挖掘从入门到放弃(一):线性回归和逻辑回归
下一篇: 数据挖掘从入门到放弃(二):决策树
Wang_AI
博客等级 码龄12年 997粉丝 162原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值