手绘10张图,把CSRF跨域攻击、JWT跨域认证说得明明白白的
作者 | 写代码的明哥
来源 | Python编程时光
这篇文章本应该是属于 HTTP 里的一部分内容,但是我看内容也挺多的,就单独划分一篇文章来讲下。
什么是跨域请求
要明白什么叫跨域请求,首先得知道什么叫域。
域,是指由 协议
+ 域名
+ 端口号
组成的一个虚拟概念。
如果两个域的协议、域名、端口号都一样,就称他们为同域,但是只要有其中一个不一样,就不是同域。
那么 跨域请求
又是什么意思呢?
简单来说,就是在一个域内请求了另一个域的资源,由于域不一致,会有安全隐患。
跨域请求的安全隐患
有一个词,叫 CSRF (Cross-site request forgery)攻击,中文名是 跨站请求伪造
。
简单来说呢,就是攻击者盗用了你的身份,以你的名义发送恶意请求,它能做的坏事有很多,比如以你的名义发邮件,发消息,购物,盗取帐号等。
CSRF 的实际工作原理是怎样的?
比如现在有两个网站,A 网站是真实受信息的网站,而 B网站是危险网站。
当你登陆 A 网站后,浏览器会存储 A 网站服务器给你生成的 sessionid 存入 cookie,有了这个 cookie ,就拥有了你的帐号权限,以后请求资料,就不用再次登陆啦。
对于真实用户来说,是便利,可对于攻击者来说,却是可乘之机。
他们可以使用各种社工学引导你点击他们的链接/网站,然后利用你的浏览器上存储的 cookie ,然后在自己的 网站B 发起对 网站A 的请求,获取一些隐私信息,做一些侵害用户权益的事情。这便是一个完整的 CSRF 攻击。
跨域请求的安全防御
完成一次完整的 CSRF 攻击,只要两个步骤:
登录受信任网站A,并本地已经存储了 Cookie
在不登出A的情况下,访问危险网站B,网站 B 诱导你发 A 发请求。
很多浏览器用户对于网络安全是无意识的,因此我们不能指望通过规范用户行为来避免CSRF攻击。
那如何从技术手段规避一定的 CSRF 攻击的风险呢?
利用浏览器的同源策略:最基础的安全策略
对请求的来源进行验证:Referer Check
使用验证码强制使用户进行交互确认,保证请求是用户发起
CSRF Token,注意不要使用 cookie 来存储token
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 字段,是有可能会被篡改的。
退一步讲,假设你使用了最安全的最新版本的浏览器,这个值无法被篡改,依旧还是有安全隐患。
因为有些用户出于某些隐私考虑,会在浏览器设置关闭这个 Referer 字段,也有的网站会使用一些技术手段使用请求不携带 Referer 字段。
因此,当你要使用 Referer Check 来做为 防御 CSRF 攻击的主要手段时,请确保你的用户群体使用的一定是最安全的最新版本的浏览器,并且默认用户不会手动关闭 Referer 。
3.3 加验证码
验证码,强制用户必须与应用进行交互,才能完成最终请求。
其实加验证码,是能很好遏制 CSRF 攻击,但是网站总不能给所有的操作都加上验证码吧,那样的话,用户估计都跑光光了,因此为了保证用户体验,验证码只能作为一种辅助手段,不能作为主要解决方案。
3.4 CSRF Token
CSRF 攻击之所以能够成功,是因为黑客可以完全伪造用户的请求,该请求中所有的用户验证信息都是存在于 cookie 中,因此黑客可以在不知道这些验证信息的情况下,直接利用用户自己的 cookie 来通过安全验证。
所以要抵御 CSRF,关键在于要在请求中放入黑客所不能伪造的信息,并且该信息不存在于 cookie 之中(不然黑客又能拿到了)。
业界普遍的防御方案是使用 CSRF Token
使用 CSRF Token 根据token验证方式的不同,也可以分为两种:
第一种:如图所示
当用户请求一个更新用户名的页面时,由服务端生成一个随机数 Token,然后放入HTML表单中传给浏览器,并且存入 session 中。
当用户提交表单请求时,表单数据会带上这个 Token 发送给服务端 ;
服务端收到表单请求后,会从表单数据里取出 Token,然后和 session 里的 token 进行对比,如果是一样的,就是合法的用户请求,将新的用户名存入数据库,如果不一样,那就是非法的请求,应当拒绝。
第二种:
当用户请求一个更新用户名的页面时,由服务端生成一个随机数 Token,然后放入HTML表单中,并且会把这个 Token 放在 cookie 里发给浏览器。
当用户提交表单请求时,表单数据会带上这个 Token 发送给服务端,并且带上携带 token 的 cookie ;
服务端收到表单请求后,会从表单数据里取出 Token,与 cookie 里的 token 进行对比,如果是一样的,就是合法的用户请求,将新的用户名存入数据库,如果不一样,那就是非法的请求,应当拒绝。
3.5 新增 Header
使用上面的 CSRF Token 已经可以避免 CSRF 攻击,但是它却有可能又引入了另一个问题。
若 CSRF Token 没有使用 cookie,就必须要将 Token 存储在服务端的 Session 中,这样就会面临几个问题
服务端每生成一个 Token,都会存放入 session 中,而随着用户请求的增多,服务端的开销会明显增大。
如果网站有多个子域,分别对应不同的服务器,比如 taobao.com 后台是服务器 a,zhibo.baotao.com 后台是 服务器b, 不同子域要想使用同一个 Token,就要求所有的服务器要能共享这个 Token。一般要有一个中心节点(且应是一个集群)来存储这个Token,这样看下来,架构就变得更加复杂了。
想要解决这些问题,可以使用我们接下来要讲的 JWT(全称:JSON Web Token)
使用了 JWT 后,有了哪些变化呢
服务器只负责生成 Token和校验Token,而不再存储Token
将服务器的压力分摊给了所有的客户端。
服务端的 鉴权不使用 cookie ,而是由新增的 Header 字段:Authorization 里的 JWT 。
JWT 是本篇文章重要知识点之一,下面我会详细说说关于 JWT 的内容。
JWT 的工作原理及目的
为了让你直观感受 JWT 的工作原理,我画了下面这张图
用户以 Web表单 的形式,将自己的用户名和密码 POST 到后端的接口。
后端核对用户名和密码成功后,会计算生成JWT Payload 字符串(具体计算方法,后续会讲),然后返回 response 给浏览器。
浏览器收到 JWT 后,将其保存在 cookie 里或者 localStorage 或者 sessionStorage 里(具体如何选,后面会说)。
后续在该域上发出的请求,都会将 JWT放入HTTP Header 中的 Authorization 字段。
后端收到新请求后,会使用密钥验证 JWT 签名。
验证通过后后端使用 JWT 中包含的用户信息进行其他相关操作,返回相应结果。
JWT 的诞生并不是解决 CSRF 跨域攻击,而是解决跨域认证的难题。
举例来说,A 网站和 B 网站是同一家公司的关联服务。现在要求,用户只要在其中一个网站登录,再访问另一个网站就会自动登录,这应该如何实现呢?
一种解决方案是 session 数据持久化,写入数据库或别的持久层。各种服务收到请求后,都向持久层请求数据。这种方案的优点是架构清晰,缺点是工程量比较大。另外,持久层万一挂了,就会单点失败。
另一种方案是服务器索性不保存 session 数据了,所有数据都保存在客户端,每次请求都发回服务器。
JWT 就是这种方案的一个优秀代表。
JWT 如何生成?
JWT 其实就是一个字符串,比如下面这样
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
仔细观察,会发现它里面有三个 .
,以 .
为分界,可以将 JWT 分为三部分。
第一部分:头部(Header)
第二部分:载荷(Payload)
第三部分:签名(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 三个部分拼成一个字符串,每个部分之间用"点"(.
)分隔,就可以返回给用户。
如何手动生成 JWT?
如果你想手动生成一个 JWT 用于测试,有两种方法
第一种:使用 https://jwt.io/ 这个网站 。
我使用前面的 header 和 payload,然后使用 secret 密钥:Python
最后生成的 JWT 结果如下
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.3wGDum3_A8tAt1bdal5CpYbIUlpHfPQxs96Ijx883kI
第二种:使用 Python 代码生成
首先安装一下 pyjwt 这个库
$ pip install pyjwt
然后就可以在代码中使用它
import jwt
import datetime
import uuidsalt = '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
Base64URL 算法
前面提到,Header 和 Payload 串型化的算法是 Base64URL。这个算法跟 Base64 算法基本类似,但有一些小的不同。
JWT 作为一个令牌(token),有些场合可能会放到 URL(比如 api.example.com/?token=xxx)。Base64 有三个字符+、/和=,在 URL 里面有特殊含义,所以要被替换掉:=被省略、+替换成-,/替换成_ 。这就是 Base64URL 算法。
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 的保存位置,可以分为如下四种
保存在 localStorage
保存在 sessionStorage
保存在 cookie
保存在 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 攻击的可能。
JWT 如何发送?
通过上面第七节的描述,其实我也讲到了 JWT 根据不同场景可以选择两种发送方式
第一种:将 JWT 放在 Header 里的
Authorization
字段,并使用Bearer
标注
'Authorization': 'Bearer ' + ${token}
第二种:把 JWT 放入 cookie ,发送给服务端,虽然发送。但是不使用它来鉴权。
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
JWT 的最佳搭配
在真正的业务中,是有可能使用 payload 来存放一些用户的敏感信息的,由于 payload 是采用 Base64URL 转换而成,它是可逆的,因此当你在 payload 存放敏感信息时,需要保证 JWT 的安全性,不能让其暴露在 『阳光』下。
为此,JWT 最好与 HTTPS 配合使用,利用 HTTPS 的非对称加密来保证 JWT 的安全。
具体是如何保障的呢?
HTTPS 是基于 SSL/TLS 的非对称加密算法工作的。
在非对称加密算法的规则下,服务器会拥有一个叫做『私钥』的东西,它是私有的,除了服务器之外,不能再有第二个人知道它。
而相对的,所有的客户端(浏览器)同时也会有一个叫做『公钥』的东西,它是对所有人公开的,任何人都可以拥有它。它与『私钥』合称为一个密钥对。
公钥和私钥的规则是:
公钥加密的东西,只有私钥能解。因此如果 JWT 的 payload 里有你的敏感信息,那也不要紧,只要把 JWT 用公钥(前提是这个公钥得是正确的,下面会说到)加密一下,那黑客就算拿到了这个密文,也无法解密,因为私钥只有服务器才有。
私钥加密的东西,所有的公钥也都能解。因此服务器发给客户端的 JWT 的payload 尽量不要有敏感信息。
那么问题又来了,如果客户端拿到的公钥,是黑客伪造的,客户端拿着这个假公钥加密自己的敏感信息,然后发出去,黑客在拿到这个用自己伪造的公钥加密的数据,非常开心,因为这个公钥对应的私钥在自己手里,自己是可以解密得到里面的数据的。
因此如何保证服务器发给客户端(浏览器)的公钥是正确的呢?
答案是通过数字证书来保证。但是由于这个不是本文的重点,因此我将这块内容放在后面的文章详细解释。
写在最后
最后,我总结一下,本文的要点:
CSRF 攻击的产生,需要cookie 的『助攻』,否则无法完成。
CRSF 是利用 cookie,而不是盗取 cookie,这点一定要明白。
但也并不是使用了 cookie 就会有 CSRF 风险,而应该说是用 cookie 去做鉴权才会有 CSRF 风险,参考 CSRF Token (把 token 存储在 cookie 的情况)和 JWT (把 token 存储在 cookie 的情况)。
CSRF Token 和 JWT 虽然都可以做到防御 CSRF 攻击,但其实无论是哪个都无法同时做到防御 CSRF 和 XSS 攻击,在阻止了 CSRF 攻击后, 需要再通过其他手段来减少 XSS 攻击的可能性。
JWT 就是一个由服务端按照一定的规则生成的字符串,
JWT 的目的是为了做一个无状态的 session,避免去频繁查询 session,减少了对服务器产生的压力,简化后端架构模型。它的主要用途是解决跨域认证的问题,而解决 CSRF 跨域攻击只是它的附带功能。
payload 是经过 base64URL 算法转换而成的字符串,是可逆的,因此尽量不要存放敏感数据,如若非要存放敏感数据,最好与 HTTPS 协议搭配使用,避免数据泄露。
JWT 的保存位置与方式,没有绝对的方案,具体如何选择要视情况而定。
推荐阅读
一键实现图像、视频卡通化,GAN又进化了
为什么说机器学习是预防欺诈的最佳工具?
Python 还能实现图片去雾?FFA 去雾算法、暗通道去雾算法用起来! | 附代码
程序员必备基础:Git 命令全方位学习
微软直播马上开始,近百岗位等你来,快戳进直播间
相关文章:

WYSE Thin Clinet 常用快捷键
1. 同时按住Ctrl Alt Up(向上方向键),即可将远程连接由全屏状态切换到Window状态2. 同时按住Ctrl Alt Down(向下方向键),即可在远程连接进程间切换(类似于Windows系统的Alt Tab功能&…
CSS3模拟IOS滑动开关
前言 H5站点需要IOS滑动按钮的效果,想了想似乎CSS3能搞起,就折腾出来了...挺简单的..请看注释效果 代码 <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <title>CSS3模拟IOS开关</title> <style t…
PyTorch 1.6、TensorFlow 2.3、Pandas 1.1同日发布!都有哪些新特性?
作者 | 肖智清出品 | AI科技大本营(ID:rgznai100)7月29日,PyTorch 1.6、TenorFlow 2.3、Pandas 1.1恰巧同时发布。这三个库都是定期滚动更新,大约每个季度更新一次小版本。在AI内卷化达到“灰飞烟灭”的今日,仅仅会对P…

ENC28j60以太网芯片驱动程序简介
转载: 本介绍可分为三块内容: 1.以太网数据帧结构 符合IEEE802.3标准的以太网帧的长度是介于64-1516字节之间。主要由目标MAC地址、源MAC地址、类型/长度字段、数据有效负载、可选填充字段和循环冗余校验组成,另外在通过以太网介质发送数据包…

在ASP.NET中获取文件属性
www.chinacs.net 2001-8-13 中文C#技术站 在ASP.NET中获取文件属性(Retrieving File Information In ASP.NET)By Steven Smith 使用ASP.NET我们可以很容易的得到文件的相关信息,包括:文件名、路径、扩展名、大小和创建以及使用日…

javascript运动系列第九篇——碰撞运动
前面的话 碰撞可以分为碰壁和互碰两种形式,上篇介绍了碰壁运动,本文将从浅入深地介绍碰撞运动的互碰形式 碰撞检测 对于互碰形式的碰撞运动来说,首先要解决的是碰撞检测。对于矩形元素的碰撞检测前面的博文已经详细介绍过,下面主要…

Asp.Net 使用 GDI+ 绘制3D饼图入门篇源码
出处:www.knowsky.com 作者:www.knowsky.com <script languageJavaScript src"/ad/ad.js"></script> topn3dpie.aspx------------------<% Page language"c#" CodeBehind"topn3dpie.aspx.cs" AutoEventW…

【Visual C++】游戏开发笔记十三 游戏输入消息处理(二) 鼠标消息处理
本系列文章由zhmxy555编写,转载请注明出处。 http://blog.csdn.net/zhmxy555/article/details/7405479作者:毛星云 邮箱: happylifemxyqq.com 欢迎邮件交流编程心得上一节我们讲解了键盘消息处理相关的知识。键盘加鼠标作为目前人机交互…
当最懂 5G 的中国移动遇见云,移动云专题赛正式启动!
根据《中国云计算产业发展白皮书》预测,2023年中国云计算产业规模将超过3000亿人民币,其中,中国政府和企业上云率将超过60%。在国家新基建战略的大力推动下,5G和云计算迎来了巨大的发展契机。作为中国移动5G战略的重要组成部分&am…

spring配置文件详解【总结】
知其然,知其所以然 <?xml version"1.0" encoding"UTF-8"?> <beans:beans xmlns"http://www.springframework.org/schema/mvc" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance…

ucontext实现的用户级多线程框架3(实现echo服务器)
前面一篇文章实现了一个抢先式的用户级多线程框架,现在用那个框架编写一个echo服务, 因为只是个实验,所以代码写得比较杂乱,还有很多可能出错的情况也没有处理,这些在今后的进一 步研究中都会慢慢修改,下面…

asp.net 2.0中用GRIDVIEW插入新记录
出处:www.knowsky.com 作者:www.knowsky.com <script languageJavaScript src"/ad/ad.js"></script> name"mq" marginwidth"0" marginheight"0" src"../../ad.html" frameborder"no…
我在攻克机器学习硕士学位的那些年
编者按:人工智能发展日趋成熟,也成为众多开发者职业生涯的首选方向。然而相较于其他领域,人工智能中的深度学习、机器学习、计算视觉、神经网络等技术更为错综复杂,进修难度也更胜一筹。对此,对于入门和想要进阶的学生…
POJ 3174 暴力枚举
思路: 暴力枚举三个点 判一判 搞定 (x1*y1x2*y2) x1、y1、x2、y2为他们两两的差 //By SiriusRen #include <cstdio> using namespace std; int n,cnt; struct Point{int x,y;}point[888]; struct ans{int x,y,z;}ans[888]; int main…
TensorFlow、PyTorch夹缝之下:后浪的进击和野望
作者 | Just出品 | AI科技大本营(rgznai100)“我发现,软件研发总会延期。”一流科技CEO袁进辉说。按照他的预期,深度学习框架OneFlow做两年就能开源给开发者检验,但时间向后延长了近一年半,“确实预计的不准…

在Win 2003中配置ASP.net环境
作者:未知大家知道,Microsoft为了更好地预防恶意用户和攻击者的攻击,在默认情况下,没有将 IIS6.0 安装到 Windows Server 2003 家族的成员上。而且,当我们最初安装 IIS6.0 时,该服务在高度安全和"锁定…

网页中的数学公式
无意中发现一个在网页中显示数学公式的解决方案,MathJax,太崇拜这些人了!他们才是真正地IT人,哪像国内我们这些民工? 代码如下: <!DOCTYPE html><html><head><title>MathJax AsciiMath Test P…

php删除目录下的所有文件和目录
<?php /*** 递归实现删除目录下的所有的文件和文件夹* param $dir 要删除的目录* param bool $deleteRootToo 是否删除根目录 默认不删除http://www.manongjc.com/article/1333.html*/ function unlinkRecursive($dir, $deleteRootToo false) {if(!$dh opendir($dir)){re…

DZX2无法读取会员短消息
我们在升级Discuz论坛时,如果没升级好,可能会出现各种各样的问题。比如登陆会员,但点“短消息”会出现错误,如下:提示:UCenter info: MySQL Query ErrorSQL:SELECT COUNT(*) FROM [Table]pm_members m WHER…

ASP.NET 如何操作文件
本文由chenyangasp版权所有,可以转载,复制,粘贴,并请注明出处,但不得修改! 在asp.net操作文件的所有concept都在system.io namespace中,这个namespace包含读写操作文件所必需的类。 本文将详细…
摊牌了:我就靠这几点,搞定了算法面试官
很多时候,你即使提前复习了这些最常见的面试算法题,你依旧无法通过算法面试!为什么?1. 你在提前准备复习的时候,在网上找了半天相应题目的分析文章,但你看了就是不懂。2. 你在面试的时候,卡壳了…

Spoooooky CSS 选择器
2019独角兽企业重金招聘Python工程师标准>>> 让我们今年有一些万圣节主题的帖子精神!我会从超过 GRAVE.eR.CSS选择器中挑选一些将冻结你骨头的选择器。也许不可能,但他们至少有点怪异。 迟钝的猫头鹰选择器(the lobotomized owl s…

关于无法创建aps.web项目的解决办法
出处:CSDN 作者:ahking <script languageJavaScript src"/ad/ad.js"></script> 1、当站点主目录没有创建应用程序: 通过FP扩展虚拟目录的方式来建立WEBAPP,步骤如下: (1)、右击站…

国内ntp时间服务器ip地址
NTP(Network Time Protocol)是由美国德拉瓦大学的David L. Mills教授于1985年提出,除了可以估算封包在网络上的往返延迟外,还可独立地估算计算机时钟偏差,从而实现在网络上的高精准度计算机校时,它是设计用…
谷歌顶级量子科学家详述他为何从谷歌辞职
加州大学圣塔芭芭拉分校(UCSB)的教授John Martinis作者 | Paul Smith-Goodson译者 | 天道酬勤,责编 | Carol 约翰马丁尼斯(John Martinis)教授从Google辞职的消息在整个量子学界引起了轩然大波。消息宣布几天后&#x…

论文笔记之:Generative Adversarial Text to Image Synthesis
Generative Adversarial Text to Image Synthesis ICML 2016 摘要:本文将文本和图像练习起来,根据文本生成图像,结合 CNN 和 GAN 来有效的进行无监督学习。 Attribute Representation: 是一个非常具有意思的方向。由图像到文本,可…

ADO.NET 2.0 中的架构
Bob BeaucheminDevelopMentor 适用于:Microsoft ADO.NET 2.0Microsoft Visual Studio 2005C# 编程语言 摘要:了解在 ADO.NET 中对于从您的数据源访问元数据的增强支持。下载相关的 SchemasSample.exe 示例代码。 本页内容 深入了解新的公共元数据 API究…

Android实现程序前后台切换效果
本文演示如何在Android中实现程序前后台切换效果。 在介绍程序实现之前,我们先看下Android中Activities和Task的基础知识。 我们都知道,一个Activity 可以启动另一个Activity,即使这个Activity是定义在别一个应用程序里的,比如说,…
如果特斯拉制造相机的梦想像激光雷达一样真正实现,它可能会帮助到更多同行...
这张来自伪激光雷达论文的图片显示了旧的黄色实点云作者 | Brad Templeton译者 | 天道酬勤,责编 | Carol特斯拉 CEO 埃隆马斯克(Elon Musk)对自动驾驶激光雷达(3D图像技术)的看法是众所周知的。他不打算在特斯拉里使用…

java分享第五天(数组)
1 声明数组变量: double[] mylist; or double mylist[]; 2 创建数组: 可以通过使用new运算符使用以下语法创建一个数组: arrayRefVarnew dataType[arraySize]; 上面的语句做了两件事: 它创建一个数据使用new dataType[…