CORS详解

文章来源: http://www.ruanyifeng.com/blog/2016/04/cors.html

之所以查cors,原因是今天发现我之前做的docker,在发布之后,竟然有个跨域问题

之前都可用,但是今天突然不可用了,想到之前遇到跨域问题,也有通过add header “Access-Control-Allow-Origin” 解决过,但是没有详细了解这块内容,只是为了解决问题临时查资料码代码,经过一番定位后,结果发现我的跨域问题并非没有吐cors响应头引起的,而是后端有报错。但是network里却没有显示出来。error_log 里却可以看到是有报错,用curl -v 查看http请求详情发现返回的httpcode 是500(Server Internal 500),导致响应头没有吐回,从而导致console显示跨域。不过当时误以为是响应头设置问题,仔细查了下这块的资料,特此手打记录一下:

cors是一个W3C标准,全称“跨域资源共享”(Cross-origin resource sharing)

它允许浏览器向跨源服务器,发出xhr请求,从而克服ajax只能同源使用的限制。

CORS机制:

cors需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10

整个cors通信过程,都是浏览器自动完成,不需要用户参与,对于开发者来说,cors通信与同源的ajax通信没有差别,代码完全一样。浏览器一旦发现ajax请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加请求,但用户不会有感觉。

因此,实现cors通信的关键是服务器,只要服务器实现了cors接口,就可以跨源通信。

浏览器将cors请求分为两类,一类是简单请求,另一类是非简单请求,只要同时满足以下两大条件,就属于简单请求:

  • 请求方法是以下三种方法之一:HEAD、GET、POST
  • HTTP头信息不超过以下几种字段

a.Accept
b.Accept-Language
c.Content-Language
d.Last-Event-ID
e.Content-Type: 只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

凡是不同时满足以上两个条件,就属于非简单请求。

  • 简单请求的基本流程:

对于简单请求,浏览器直接发出cors请求,具体来说,就是在头信息中,增加一个Origin字段。

下面是一个例子,浏览器发现这次跨源xhr请求是简单请求,就自动在头信息之中,添加一个Origin字段。

GET /cors HTTP/1.1
Origin: http://api.bob.com
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

上面的头信息中,Origin字段用来说明,本次请求来自哪个源(协议+域名+端口)。服务器根据这个值,决定是否同意这次请求。

如果Origin指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应。浏览器发现,这个回应的头信息里没有包含Access-Control-Allow-Origin字段,就知道出错了,从而抛出一个错误,被xhr的onerror回调函数捕获。ps: 这种错误无法通过状态码识别,因为http code有可能是200。

如果Origin指定的域名在许可范围内,服务器返回的响应,会多出几个头信息字段。

Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset=utf-8

上面的头信息之中,有三个与cors请求相关的字段,都以Access-Control-开头。

  • Access-Control-Allow-Origin

该字段是必须的,它的值要么是请求时Orgin字段的值,要么是一个*,表示接受任意域名的请求。

  • Access-Control-Allow-Credentials

该字段可选,它的值是一个布尔值,表示是否允许发送Cookie, 默认情况下,Cookie不包括在cors请求中,设为true, 即表示服务器明确许可,Cookie可以包含在请示中,一起发给服务器。这个值也只能设为true, 如果服务器不再浏览器发送Cookie, 删除该字段即可。

  • Access-Control-Expose-Headers

该字段可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。上面的例子指定,getResponseHeader(‘FooBar’)可以返回FooBar字段的值。

  • withCredentials 属性

上面说到,cors请求默认不发送Cookie和http认证信息。如果要把Cookie发到服务器,一方面要服务器同意,指定Access-Control-Allow-Credentials字段

Access-Control-Allow-Credentials: true

另一方面,开发者必须在ajax请求中打开withCredentials属性

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

否则,即使服务器同意发送Cookie, 浏览器也不会发送。或者,服务器要求设置Cookie, 浏览器也不会处理。

但是,如果省略withCredentials设置,有的浏览器还是会一起发送Cookie。这时,可以显示关闭withCredentials。

xhr.withCredentials = false;

需要注意的是,如果要发送Cookie, Access-Control-Allow-Origin就不能设为*, 必须指定明确的,与请求网页一致的域名。同时,Cookie依然遵循同源政策,只有用服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,且(跨源)原网页代码中的document.cookie也无法读取服务器名下的cookie。

  • 非简单请求

预检请求

非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json。

非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为”预检”请求(preflight)。

浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。

下面是一段浏览器的JavaScript脚本。

var url = 'http://api.alice.com/cors';
var xhr = new XMLHttpRequest();
xhr.open('PUT', url, true);
xhr.setRequestHeader('X-Custom-Header', 'value');
xhr.send();

上面代码中,HTTP请求的方法是PUT,并且发送一个自定义头信息X-Custom-Header

浏览器发现,这是一个非简单请求,就自动发出一个”预检”请求,要求服务器确认可以这样请求。下面是这个”预检”请求的HTTP头信息。

OPTIONS /cors HTTP/1.1
Origin: http://api.bob.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

“预检”请求用的请求方法是OPTIONS,表示这个请求是用来询问的。头信息里面,关键字段是Origin,表示请求来自哪个源。

除了Origin字段,”预检”请求的头信息包括两个特殊字段。

(1)Access-Control-Request-Method

该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法,上例是PUT

(2)Access-Control-Request-Headers

该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段,上例是X-Custom-Header

预检请求回应

服务器收到”预检”请求以后,检查了OriginAccess-Control-Request-MethodAccess-Control-Request-Headers字段以后,确认允许跨源请求,就可以做出回应。

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain

上面的HTTP回应中,关键的是Access-Control-Allow-Origin字段,表示http://api.bob.com可以请求数据。该字段也可以设为星号,表示同意任意跨源请求。

如果浏览器否定了”预检”请求,会返回一个正常的HTTP回应,但是没有任何CORS相关的头信息字段。这时,浏览器就会认定,服务器不同意预检请求,因此触发一个错误,被XMLHttpRequest对象的onerror回调函数捕获。控制台会打印出如下的报错信息。

XMLHttpRequest cannot load http://api.alice.com.
Origin http://api.bob.com is not allowed by Access-Control-Allow-Origin.

服务器回应的其他cors相头字段:

Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 1728000

(1)Access-Control-Allow-Methods

该字段必需,它的值是逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法。注意,返回的是所有支持的方法,而不单是浏览器请求的那个方法。这是为了避免多次”预检”请求。

(2)Access-Control-Allow-Headers

如果浏览器请求包括Access-Control-Request-Headers字段,则Access-Control-Allow-Headers字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在”预检”中请求的字段。

(3)Access-Control-Allow-Credentials

该字段与简单请求时的含义相同。

(4)Access-Control-Max-Age

该字段可选,用来指定本次预检请求的有效期,单位为秒。上面结果中,有效期是20天(1728000秒),即允许缓存该条回应1728000秒(即20天),在此期间,不用发出另一条预检请求。

openssl生成ca根证书及颁发证书

之前分享过一篇文章: https://www.clarkhu.net/?p=1250 ,生成证书请求,私钥及证书脚本,这篇文章有一个弊端,因为只生成了自签名的证书,并没有生成CA根证书,所以证书的小绿锁上是有问题的,一直显示不安全,想要生成安全的自签名证书,必须要生成私有的CA根证书,然后用CA根证书生成服务器的证书,这样生成的自签名证书才能在浏览器地址栏,显示成绿色。(只要把CA根证书导入浏览器就可以受信了)

总体流程如下:

1.设置openssl的环境变量,OPENSSL_CONF=openssl.cnf路径(这一步不是必需的,可以后续指定好路径也行),查看openssl.cnf的路径:openssl version -a [/etc/pki/tls]

2.将openssl配置文件中的 req_extensions = v3_req注释取消掉

3.去掉[req_distinguished_name]里0.xxx开头的部分

4.修改[ v3_req ]和[ v3_ca ]内容

[ v3_req ]
extendedKeyUsage=serverAuth(增强型密钥用法,服务端验证)
subjectAltName = @alt_names(使用者备用名称)

[ v3_ca ]
basicConstraints = CA:true(使用基本约束)

5.增加[ alt_names ],里面的内容可以增加多个DNS.X,IP.X,其中IP可以不填,但是DNS一定要和你的网站域名能匹配,比如你的网站是www.my.com,那么你可以设置为DNS.1=*.my.com

[ alt_names ]
DNS.1 = 127.0.0.1
IP.1 = 127.0.0.1

6.要生成一个根证书私钥

  • -aes256代表加密算法,还可以选择des3等
  • 1024代表加密强度
  • -passout pass:123456 这里直接输入密码

    openssl genrsa -passout pass:123456 -aes256 -out ca_private.key 2048

7.使用根证书私钥生成csr(证书签名请求)

openssl req -passin pass:123456 -new -key ca_private.key -out ca.csr -subj "/C=CN/ST=ST/L=CITY/O=o/OU=ou/CN=cn" 

8.使用根证书私钥和csr生成根证书

  • -days后面是天数,尽可能填大一点
  • 天数后面是使用的算法,不要选择sha1,谷歌浏览器会认为不安全
  • -extensions表示扩展属性
  • -extfile表示扩展属性所在的文件
openssl x509 -req -passin pass:123456 -days 18250 -sha256 -signkey ca_private.key -extensions v3_ca -extfile /etc/pki/tls/openssl.cnf -in ca.csr -out ca.cer

上面这空虚ca.cer就是CA的根证书,之后需要导入到浏览器的受信根证书区域的

9.生成服务端证书私钥

 openssl genrsa -out server_private.key 2048

10.生成服务端证书签名请求

 openssl req -new -key server_private.key -out server.csr -subj "/C=CN/ST=ST/L=CITY/O=o/OU=ou/CN=cn"

11.生成服务端证书

openssl x509 -req -passin pass:123456 -days 18250 -sha256 -extensions v3_req -extfile openssl.cnf -CA ca.cer -CAkey ca_private.key -CAserial ca.srl -CAcreateserial -in server.csr -out server.cer 

12.CER转PEM

openssl x509 -in server.cer

最后的效果:

证书信息
证书链(可以看到CA根证书)

PS: 要把ca.cer导入到受信根证书区域才能看到证书链

受信息的根证书颁发机构

其他相关文档: https://www.jianshu.com/p/81dbcde4fd7c

生成证书请求、证书和私钥脚本

!/bin/sh
create self-signed server certificate:
read -p "Enter your domain [www.example.com]: " DOMAIN
echo "Create server key…"
openssl genrsa -des3 -out $DOMAIN.key 2048
echo "Create server certificate signing request…"
 SUBJECT="/C=CN/ST=Guangdong/L=Shenzhen/O=Clark/OU=Clark/CN=$DOMAIN/emailAddress=xxx@clarkhu.net"
openssl req -new -subj $SUBJECT -key $DOMAIN.key -out $DOMAIN.csr
echo "Remove password…"
mv $DOMAIN.key $DOMAIN.origin.key
openssl rsa -in $DOMAIN.origin.key -out $DOMAIN.key
echo "Sign SSL certificate…"
openssl x509 -req -days 3650 -in $DOMAIN.csr -signkey $DOMAIN.key -out $DOMAIN.pem
echo "TODO:"
echo "Copy $DOMAIN.pem to /usr/local/nginx/conf/$DOMAIN.pem"
echo "Copy $DOMAIN.key to /usr/local/nginx/conf/$DOMAIN.key"
echo "Add configuration in nginx:"
echo "server {"
echo "    …"
echo "    listen 443 ssl;"
echo "    ssl_certificate     /usr/local/nginx/conf/$DOMAIN.pem;"
echo "    ssl_certificate_key /usr/local/nginx/conf/$DOMAIN.key;"
echo "}"

openssl证书请求和自签名命令详解

文章出处:https://linux.cn/article-7248-1.html
最近在做https改造,所以最近几篇的文章都是关于https证书相关的

1、密钥、证书请求、证书概要说明

在证书申请签发过程中,客户端涉及到密钥、证书请求、证书这几个概念,初学者可能会搞不清楚三者的关系,网上有的根据后缀名来区分三者,更让人一头雾水。我们以申请证书的流程说明三者的关系。客户端(相对于CA)在申请证书的时候,大体上有三个步骤:

  • 第一步:生成客户端的密钥,即客户端的公私钥对,且要保证私钥只有客户端自己拥有。
  • 第二步:以客户端的密钥和客户端自身的信息(国家、机构、域名、邮箱等)为输入,生成证书请求文件。其中客户端的公钥和客户端信息是明文保存在证书请求文件中的,而客户端私钥的作用是对客户端公钥及客户端信息做签名,自身是不包含在证书请求中的。然后把证书请求文件发送给CA机构。
  • 第三步:CA机构接收到客户端的证书请求文件后,首先校验其签名,然后审核客户端的信息,最后CA机构使用自己的私钥为证书请求文件签名,生成证书文件,下发给客户端。此证书就是客户端的身份证,来表明用户的身份。

至此客户端申请证书流程结束,其中涉及到证书签发机构CA,CA是被绝对信任的机构。如果把客户端证书比作用户身份证,那么CA就是颁发身份证的机构,我们以https为例说明证书的用处。

为了数据传输安全,越来越多的网站启用https。在https握手阶段,服务器首先把自己的证书发送给用户(浏览器),浏览器查看证书中的发证机构,然后在机器内置的证书中(在PC或者手机上,内置了世界上著名的CA机构的证书)查找对应CA证书,然后使用内置的证书公钥校验服务器的证书真伪。如果校验失败,浏览器会提示服务器证书有问题,询问用户是否继续。

例如12306网站,它使用的自签名的证书,所以浏览器会提示证书有问题,在12306的网站上有提示下载安装根证书,其用户就是把自己的根证书安装到用户机器的内置证书中,这样浏览器就不会报证书错误。但是注意,除非特别相信某个机构,否则不要在机器上随便导入证书,很危险。

openssl req 命令

发现其参数多而复杂,还有许多没有用到过的参数。但是在实际应用中我们使用到的参数很有限,我们根据req的基本功能来学习。

req的基本功能主要有两个:生成证书请求和生成自签名证书。其他还有一些校验、查看请求文件等功能,示例会简单说明下。参数说明如下

[new/x509]

当使用-new选取的时候,说明是要生成证书请求,当使用x509选项的时候,说明是要生成自签名证书。

[key/newkey/keyout]

key和newkey是互斥的,key是指定已有的密钥文件,而newkey是指在生成证书请求或者自签名证书的时候自动生成密钥,然后生成的密钥名称有keyout参数指定。
当指定newkey选项时,后面指定rsa:bits说明产生rsa密钥,位数由bits指定。指定dsa:file说明产生dsa密钥,file是指生成dsa密钥的参数文件(由dsaparam生成)

[in/out/inform/outform/keyform]

in选项指定证书请求文件,当查看证书请求内容或者生成自签名证书的时候使用
out选项指定证书请求或者自签名证书文件名,或者公钥文件名(当使用pubkey选项时用到),以及其他一些输出信息。
inform、outform、keyform分别指定了in、out、key选项指定的文件格式,默认是PEM格式。

[config]

参数文件,默认是/etc/ssl/openssl.cnf(ubuntu12.04),根据系统不同位置不同。该文件包含生成req时的参数,当在命令行没有指定时,则采用该文件中的默认值。
除上述主要参数外,还有许多其他的参数,不在一一叙述,有兴趣的读者可以查看req的man手册

req使用实例

1、使用已有私钥生成证书请求

使用原有的RSA密钥生成证书请求文件,输入主体相关信息:

根据私钥生成证书请求

使用原有的RSA密钥生成证书请求文件,指定-batch选项,主体信息从配置文件读取:

指定batch 主体信息从配置文件读取

使用原有的RSA密钥生成证书请求文件,指定-subj选项,主体信息由命令行subj指定:

指定subj,主体信息由命令行指定

可以看到公钥和请求信息:

查看公钥和请求信息

2、自动生成密钥,生成证书请求文件

自动生成1024位RSA密钥,并生成证书请求

自动生成1024位RSA密钥,并生成证书请求文件,指定-nodes文件,密钥文件不加密:

自动生成1024位DSA密钥参数:

自动生成1024位DSA密钥,并生成证书请求文件,指定-nodes文件,密钥文件不加密:

3、生成自签名证书

生成自签名证书,与req参数一样,只需要把req修改为x509即可:

查看证书文件:

查看证书文件

4、查看证书请求内容
生成证书请求:

查看证书请求内容,subject指定输出主体:

5、校验证书请求文件

指定verify指令,校验证书请求文件,其操作时提取请求文件中的公钥来验证签名信息:

还有相关比较好的文章说明: https://www.cnblogs.com/guogangj/p/4118605.html

CA证书详解

文章来源: https://www.cnblogs.com/handsomeBoys/p/6556336.html , 此文章个人觉得讲的比较详细到位,之前也有过一些关于https 公钥和私钥分享,
http://www.clarkhu.net/?p=131

1.什么是CA证书。

看过一些博客,写的比较形象具体。

◇ 普通的介绍信

  想必大伙儿都听说过介绍信的例子吧?假设 A 公司的张三先生要到 B 公司去拜访,但是 B 公司的所有人都不认识他,他咋办捏?常用的办法是带公司开的一张介绍信,在信中说:兹有张三先生前往贵公司办理业务,请给予接洽……云云。然后在信上敲上A公司的公章。

  张三先生到了 B 公司后,把介绍信递给 B 公司的前台李四小姐。李小姐一看介绍信上有 A 公司的公章,而且 A 公司是经常和 B 公司有业务往来的,这位李小姐就相信张先生不是歹人了。

这里,A公司就是CA证书

◇ 引入中介机构的介绍信

  好,回到刚才的话题。如果和 B 公司有业务往来的公司很多,每个公司的公章都不同,那前台就要懂得分辨各种公章,非常滴麻烦。所以,有某个中介公司 C,发现了这个商机。C公司专门开设了一项“代理公章”的业务。

  今后,A 公司的业务员去 B 公司,需要带2个介绍信:

  介绍信1

  含有 C 公司的公章及 A 公司的公章。并且特地注明:C 公司信任 A 公司。

  介绍信2

  仅含有 A 公司的公章,然后写上:兹有张三先生前往贵公司办理业务,请给予接洽……云云。

  某些不开窍的同学会问了,这样不是增加麻烦了吗?有啥好处捏?

  主要的好处在于,对于接待公司的前台,就不需要记住各个公司的公章分别是啥样子的;他/她只要记住中介公司 C 的公章即可。当他/她拿到两份介绍信之后,先对介绍信1的 C 公章,验明正身;确认无误之后,再比对介绍信1和介绍信2的两个 A 公章是否一致。如果是一样的,那就可以证明介绍信2是可以信任的了。

◇ 什么是证书?

  “证书”英文也叫“digital certificate”或“public key certificate”(专业的解释看“这里”)。

  它是用来证明某某东西确实是某某东西的东西(是不是像绕口令?)。通俗地说,证书就好比例子里面的公章。通过公章,可以证明该介绍信确实是对应的公司发出的。

  理论上,人人都可以找个证书工具,自己做一个证书。那如何防止坏人自己制作证书出来骗人捏?请看后续 CA 的介绍。

◇ 什么是CA?

  CA是Certificate Authority的缩写,也叫“证书授权中心”。(专业的解释看“这里”)

  它是负责管理和签发证书的第三方机构,就好比例子里面的中介——C 公司。一般来说,CA必须是所有行业和所有公众都信任的、认可的。因此它必须具有足够的权威性。就好比A、B两公司都必须信任C公司,才会找 C 公司作为公章的中介。

◇ 什么是CA证书?

  CA 证书,顾名思义,就是CA颁发的证书。

  前面已经说了,人人都可以找工具制作证书。但是你一个小破孩制作出来的证书是没啥用处的。因为你不是权威的CA机关,你自己搞的证书不具有权威性。

  这就好比上述的例子里,某个坏人自己刻了一个公章,盖到介绍信上。但是别人一看,不是受信任的中介公司的公章,就不予理睬。坏蛋的阴谋就不能得逞啦。

  文本后续提及的证书,若无特殊说明,均指 CA 证书。

2.证书的签发过程:

a.服务方 S 向第三方机构CA提交公钥、组织信息、个人信息(域名)等信息并申请认证;

b.CA 通过线上、线下等多种手段验证申请者提供信息的真实性,如组织是否存在、企业是否合法,是否拥有域名的所有权等;

c.如信息审核通过,CA 会向申请者签发认证文件-证书。

证书包含以下信息:申请者公钥、申请者的组织信息和个人信息、签发机构 CA 的信息、有效时间、证书序列号等信息的明文,同时包含一个签名;

签名的产生算法:首先,使用散列函数计算公开的明文信息的信息摘要,然后,采用 CA 的私钥对信息摘要进行加密,密文即签名;

d.客户端 C 向服务器 S 发出请求时,S 返回证书文件;

e.客户端 C 读取证书中的相关的明文信息,采用相同的散列函数计算得到信息摘要,然后,利用对应 CA 的公钥解密签名数据,对比证书的信息摘要,如果一致,则可以确认证书的合法性,即公钥合法;

f.客户端然后验证证书相关的域名信息、有效时间等信息;

g.客户端会内置信任 CA 的证书信息(包含公钥),如果CA不被信任,则找不到对应 CA 的证书,证书也会被判定非法。

在这个过程注意几点:

1.申请证书不需要提供私钥,确保私钥永远只能服务器掌握;

2.证书的合法性仍然依赖于非对称加密算法,证书主要是增加了服务器信息以及签名;

3.内置 CA 对应的证书称为根证书,颁发者和使用者相同,自己为自己签名,即自签名证书;

4.证书=公钥+申请者与颁发者信息+签名;

3.http存在的问题(引用:http://blog.csdn.net/wangjun5159/article/details/51510594)

http通信存在的问题

  • 容易被监听 
    • http通信都是明文,数据在客户端与服务器通信过程中,任何一点都可能被劫持。比如,发送了银行卡号和密码,hacker劫取到数据,就能看到卡号和密码,这是很危险的
  • 被伪装 
    • http通信时,无法保证通行双方是合法的,通信方可能是伪装的。比如你请求www.taobao.com,你怎么知道返回的数据就是来自淘宝,中间人可能返回数据伪装成淘宝。
  • 被篡改 
    • hacker中间篡改数据后,接收方并不知道数据已经被更改

共享密钥加密和公开密钥加密

后续内容的需要,这里插播一段共享密钥加密和公开密钥加密

  • 共享密钥加密 
    • 共享密钥的加密密钥和解密密钥是相同的,所以又称为对称密钥
  • 公开密钥加密 
    • 加密算法是公开的,密钥是保密的。公开密钥分为私有密钥和公有密钥,公有密钥是公开的,任何人(客户端)都可以获取,客户端使用公有密钥加密数据,服务端用私有密钥解密数据。
  • 异同 
    • 共享密钥加密与公开密钥加密相比,加解密处理速度快,但公开密钥更适应互联网下使用

https解决的问题

https很好的解决了http的三个缺点(被监听、被篡改、被伪装),https不是一种新的协议,它是http+SSL(TLS)的结合体,SSL是一种独立协议,所以其它协议比如smtp等也可以跟ssl结合。https改变了通信方式,它由以前的http—–>tcp,改为http——>SSL—–>tcp;https采用了共享密钥加密+公开密钥加密的方式

  • 防监听 
    • 数据是加密的,所以监听得到的数据是密文,hacker看不懂。
  • 防伪装 
    • 伪装分为客户端伪装和服务器伪装,通信双方携带证书,证书相当于身份证,有证书就认为合法,没有证书就认为非法,证书由第三方颁布,很难伪造
  • 防篡改 
    • https对数据做了摘要,篡改数据会被感知到。hacker即使从中改了数据也白搭。

https连接过程

  • 客户端发送请求到服务器端
  • 服务器端返回证书和公开密钥,公开密钥作为证书的一部分而存在
  • 客户端验证证书和公开密钥的有效性,如果有效,则生成共享密钥并使用公开密钥加密发送到服务器端
  • 服务器端使用私有密钥解密数据,并使用收到的共享密钥加密数据,发送到客户端
  • 客户端使用共享密钥解密数据
  • SSL加密建立………

客户端认证的通信的过程

  • 客户端需要认证的过程跟服务器端需要认证的过程基本相同,并且少了最开始的两步。这种情况都是证书存储在客户端,并且应用场景比较少,一般金融才使用,比如支付宝、银行客户端都需要安装证书

后续的问题

  • 怎样保证公开密钥的有效性 
    • 你也许会想到,怎么保证客户端收到的公开密钥是合法的,不是伪造的,证书很好的完成了这个任务。证书由权威的第三方机构颁发,并且对公开密钥做了签名。
  • https的缺点 
    • https保证了通信的安全,但带来了加密解密消耗计算机cpu资源的问题 ,不过,有专门的https加解密硬件服务器
  • 各大互联网公司,百度、淘宝、支付宝、知乎都使用https协议,为什么? 
    • 支付宝涉及到金融,所以出于安全考虑采用https这个,可以理解,为什么百度、知乎等也采用这种方式?为了防止运营商劫持!http通信时,运营商在数据中插入各种广告,用户看到后,怒火发到互联网公司,其实这些坏事都是运营商(移动、联通、电信)干的,用了https,运营商就没法插播广告篡改数据了。

    4.比较完整的过程:

    1. 客户端发起HTTPS请求

      这个没什么好说的,就是用户在浏览器里输入一个https网址,然后连接到server的443端口。

      2. 服务端的配置

      采用HTTPS协议的服务器必须要有一套数字证书,可以自己制作,也可以向组织申请。区别就是自己颁发的证书需要客户端验证通过,才可以继续访问,而使用受信任的公司申请的证书则不会弹出提示页面(startssl就是个不错的选择,有1年的免费服务)。这套证书其实就是一对公钥和私钥。如果对公钥和私钥不太理解,可以想象成一把钥匙和一个锁头,只是全世界只有你一个人有这把钥匙,你可以把锁头给别人,别人可以用这个锁把重要的东西锁起来,然后发给你,因为只有你一个人有这把钥匙,所以只有你才能看到被这把锁锁起来的东西。

      3. 传送证书

      这个证书其实就是公钥,只是包含了很多信息,如证书的颁发机构,过期时间等等。

      4. 客户端解析证书

      这部分工作是有客户端的TLS来完成的,首先会验证公钥是否有效,比如颁发机构,过期时间等等,如果发现异常,则会弹出一个警告框,提示证书存在问题。如果证书没有问题,那么就生成一个随机值。然后用证书对该随机值进行加密。就好像上面说的,把随机值用锁头锁起来,这样除非有钥匙,不然看不到被锁住的内容。

      5. 传送加密信息

      这部分传送的是用证书加密后的随机值,目的就是让服务端得到这个随机值,以后客户端和服务端的通信就可以通过这个随机值来进行加密解密了。

      6. 服务段解密信息

      服务端用私钥解密后,得到了客户端传过来的随机值(私钥),然后把内容通过该值进行对称加密。所谓对称加密就是,将信息和私钥通过某种算法混合在一起,这样除非知道私钥,不然无法获取内容,而正好客户端和服务端都知道这个私钥,所以只要加密算法够彪悍,私钥够复杂,数据就够安全。

      7. 传输加密后的信息

      这部分信息是服务段用私钥加密后的信息,可以在客户端被还原。

      8. 客户端解密信息

      客户端用之前生成的私钥解密服务段传过来的信息,于是获取了解密后的内容。整个过程第三方即使监听到了数据,也束手无策。

    5.总结整个过程:

    1.服务器向CA机构获取证书(假设这个证书伪造不了),当浏览器首次请求服务器的时候,服务器返回证书给浏览器。(证书包含:公钥+申请者与颁发者的相关信息+签名)

    2.浏览器得到证书后,开始验证证书的相关信息,证书有效(没过期等)。(验证过程,比较复杂,详见上文)。

    3.验证完证书后,如果证书有效,客户端是生成一个随机数,然后用证书中的公钥进行加密,加密后,发送给服务器,服务器用私钥进行解密,得到随机数。之后双方便开始用该随机数作为钥匙,对要传递的数据进行加密、解密。

    Web安全注意事项总览

    Web安全可以分为:系统/服务器安全,DB安全,代码安全,业务安全,登录安全等

    服务器安全

    • php-fpm的启动用户的设置,不要以root启动,master就root,worker不能是root,一般为nobody或www。php-fpm.conf配置文件里设置
    • mysql的启动用户
    • nginx的启动用户,非root启动,一般用nobody启动
    • 上传目录和下载目录的权限的设置,上传文件的文件名校验等
    • php.ini文件,disable_functions设置关闭危险函数,关闭注册全局变量(register_globals off),magic_quotes_gpc on 防止sql注入,display_errors=off 关闭错误显示
    • 脚本,webroot等目录的权限设置
    • 线上debug关掉
    • open_basedir设置,避免php脚本访问不应该访问的文件
    • 服务器的安全组入站规则,iptable设置

    DB安全

    • 账号密码密文存储
    • web账号,运维账号,值班账号分开
    • 每个账号授权的host 设置适宜,不能扩大

    登录安全

    • 校验码+噪点
    • 登录密码的复杂性校验,字母+数字+大小写+非连续数字
    • 多次登录失败(冻结账号)
    • 离职的账号不能登录(如果内部平台的话,可以考虑)
    • 三个月无feed的账号可以冻结(如果是内部平台的话,可以考虑)

    代码安全:

    • 注意人为输入的内容输出到页面的需要clean,防止xss注入
    • 注意sql注入,连接sql时,要对人为输入的内容clean。

    业务安全:

    • 视具体业务情况做适当的校验

    前端安全之XSS

    XSS, 即为(Cross Site Scripting), 中文名为跨站脚本, 是发生在目标用户的浏览器层面上的,当渲染DOM树的过程成发生了不在预期内执行的JS代码时,就发生了XSS攻击。
    跨站脚本的重点不在‘跨站’上,而在于‘脚本’上。大多数xss攻击的主要方式是嵌入一段远程或第三方域上的js代码,实际上是在目标网站的作用域下执行了这段js代码。

    XSS攻击方式

    反射型xss:也叫非持久型xss,是指发生请求时,xss代码出现在请求url中,作为参数提交到服务器,服务器解析并响应,响应结果中包含了xss代码,最后浏览器解析并执行。

    存储型xss:也叫持久型xss, 主要是将xss代码发送到服务器(不管是数据,内存还是文件系统等),然后在下次请求页面的时候就不用带上xss代码了。
    最典型的就是留言板xss , 用户提交了一条包含xss代码的留言到数据库。当目标用户查询留言时,那些留言的内容会从服务器解析之后加载出来。浏览器发现有xss代码,就当做正常的html和js解析执行。xss攻击就发生了。

    DOM XSS:Dom xss攻击不同于反射型xss和存储型xss, Dom xss代码不需要服务器端的解析响应的直接参与,而是通过浏览器端的dom解析,这完全是客户端的事情。

    XSS危害

    通过document.cookie盗取cookie
    使用js或css破坏页面正常的结构与样式
    流量劫持(通过访问某段具有window.location.href定位到其他页面)
    Dos攻击:利用合理的客户端请求来占用过多的服务器资源,从而使合法用户无法得到服务器响应。
    利用iframe、frame、XMLHttpRequest或上述Flash等方式,以(被攻击)用户的身份执行一些管理动作,或执行一些一般的
    如发微博、加好友、发私信等操作。
    利用可被攻击的域受到其他域信任的特点,以受信任来源的身份请求一些平时不允许的操作,如进行不当的投票活动。

    XSS防御

    对Cookie的保护
    对重要的cookie设置httpOnly,防止客户端通过document.cookie读取cookie。服务端可以设置此字段。
    对用户输入数据的处理
    编码:不能对用户输入的内容都保持原样,对用户输入的数据进行字符实体编码。对于字符实体的概念可以参考文章底部给出的参考链接。
    解码:原样显示内容的时候必须解码,不然显示不到内容了。
    过滤:把输入的一些不合法的东西都过滤掉,从而保证安全性。如移除用户上传的DOM属性,如onerror,移除用户上传的Style节点,iframe, script节点等。
    存在一个parse函数,对输入的数据进行处理,返回处理之后的数据对输入的数据(如DOM节点)进行解码(使用第三方库 he.js)过滤掉一些元素有危害的元素节点与属性节点。如script标签,onerror事件等。(使用第三方库HTMLParser.js)


    一旦在DOM解析过程成出现不在预期内的改变(JS代码执行或样式大量变化时),就可能发生XSS攻击
    XSS分为反射型XSS,存储型XSS和DOM XSS
    1.反射型XSS是在将XSS代码放在URL中,将参数提交到服务器。服务器解析后响应,在响应结果中存在XSS代码,最终通过浏览器解析执行。
    2.存储型XSS是将XSS代码存储到服务端(数据库、内存、文件系统等),在下次请求同一个页面时就不需要带上XSS代码了,而是从服务器读取。
    3.DOM XSS的发生主要是在JS中使用eval造成的,所以应当避免使用eval语句。
    4.XSS危害有盗取用户cookie,通过JS或CSS改变样式,DDos造成正常用户无法得到服务器响应。
    5.XSS代码的预防主要通过对数据解码,再过滤掉危险标签、属性和事件等。

    CSRF跨站点请求伪造

    全名:Cross Site Request Forgery, 翻译成中文就是跨站点请求伪造
    它是一种常见的web攻击,但很多开发者对它很陌生。CSRF也是web安全中最容易被忽略的一种攻击方式。
    CSRF攻击者在用户已经登录目标网站之后,诱使用户访问一个攻击页面,利用目标网站对用户的信任,以用户身份在攻击页面对目标网站发起伪造用户操作的请求,达到攻击目的。
    http://blog.sohu.com/manage/entry.do?m=delete&id=12345
    这个url同时还存在CSRF漏洞,我们将尝试利用csrf漏洞,删除编号为12345的博客文章,这篇文章的标题是”test1″
    攻击者首先在自己的域构造一个页面:
    www.a.com/csrf.html
    其内容为:
    <img src=”http://blog.sohu.com/manage/entry.do?m=delete&id=12345″>
    使用一个img标签,其地址指向删除博客文章的链接。
    访问了这个页面,博客文章就被删了。
    回顾整个攻击过程,攻击者仅仅诱使用户访问了一个页面,就以该用户身份在第三方站点里执行了一次操作,试想,如果这张图片是展示在某个论坛,某个博客,甚至搜狐的一些用户空间中,会产生什么效果呢?只需要经过精心的设计, 就能够起到更大的破坏作用。
    这个删除博客文章的请求,是攻击者所伪造的,所以这种攻击就叫做“跨站点请求伪造”

    CSRF的防御:
    a. 验证码
        验证码被认为是对抗csrf攻击最简洁而有效的防御方法。
        csrf 攻击的时候,往入是在用户不知情的情况下构造了网络请求,而验证码,则强制用户必须与应用进行交互,才能完成最终请求。
    b.Referer check
        常见的互联网应用,页面与页面之间都具有一定的逻辑关系,这就使得每个正常请求的Referer具有一定的规律。
        即使我们能够通过检查Referer是否合法来判断用户是否被CSRF攻击,也仅仅是满足了防御的充分条件
        Referer check的缺陷在于:服务器并非什么时候都能取到Referer。很多用户出于隐私保护的考虑,限制了Referer的发送。
    c. Anti CSRF token       
     CSRF的本质是:所有参数都是可以被攻击者猜测到的。
        出于这个原因,可以想到一个解决方案:把参数加密,或者使用一些随机数,从而让攻击者无法猜测到参数值。这是“不可预测性原则”的一种应用。

    举例:
    简单版
    假如博客园有个加关注的GET接口,blogUserGuid参数很明显是关注人Id, 如下:
    http://www.cnblogs.com/mvc/Follow/FollowBlogger.aspx?blogUserGuid=4e8c33d0-77fe-df11-ac81-842b2b196315
    那我只需要在我的一篇博文内容里写一个img标签:
    <img style=”width:0;” src=”http://www.cnblogs.com/mvc/Follow/FollowBlogger.aspx?blogUserGuid=4e8c33d0-77fe-df11-ac81-842b2b196315″   />
    那么只要有人打开我这篇博文,那不会自动关注我。

    升级版:
    假如博客园还是有个加关注的接口,不过已经限制了只获取POST请求的数据。这个时候就做一个第三方的页面,但里面包含form提交代码,然后通过QQ,,邮箱等社交工具传播,诱惑用户去打开,那打开博客园的用户就中招了。

    <!DOCTYPE HTML>
    <html lang=”en-US”>
    <head><title>CSRF SHOW</title></head>     
    <body>          
    <!–不嵌iframe会跳转–>          
    <iframe style=”display:none;”>
                    <form  name=”form1″ action=”http://www.cnblogs.com/mvc/Follow/FollowBlogger.aspx” method=”post”>                    
    <input type=”hidden” name=”blogUserGuid” value=”4e8c33d0-77fe-df11-ac81-842b2b196315″/>                    
    <input type=”submit” value>               
    </form>               

    <script>
    document.forms.form1.submit();
    </script>          
    </iframe>     
    </body>
    </html>

    进阶版:
    假如博客园还是有个加关注的接口,已经限制POST,但博文内容是直接贴进HTML(未过滤),那就遭受XSS攻击。那么就可以直接把上面代码嵌入博文,那么只要有人打开我这篇博文,还是会自动关注我,这组合攻击方式称为XSRF。
    本质原因:
    CSRF攻击是源于Web的隐式身份验证机制!Web的身份验证机制虽然可以保证一个请求是来自于某个用户的浏览器,但却无法保证该请求是用户批准发送的。CSRF攻击的一般是由服务端解决。

    防御手段:
    1. 尽量使用POST,限制GET
    2. 浏览器Cookie策略
    3. 加验证码
    验证码,强制用户必须与应用进行交互,才能完成最终请求。在通常情况下,验证码能很好遏制CSRF攻击。但是出于用户体验考虑,网站不能给所有的操作都加上验证码。因此验证码只能作为一种辅助手段,不能作为主要解决方案。
    4. Referer Check
    Referer Check在Web最常见的应用就是“防止图片盗链”。同理,Referer Check也可以被用于检查请求是否来自合法的“源”(Referer值是否是指定页面,或者网站的域),如果都不是,那么就极可能是CSRF攻击。
    但是因为服务器并不是什么时候都能取到Referer,所以也无法作为CSRF防御的主要手段。但是用Referer Check来监控CSRF攻击的发生,倒是一种可行的方法。
    5. Anti CSRF Token
    现在业界对CSRF的防御,一致的做法是使用一个Token(Anti CSRF Token)。
    例子:
    1. 用户访问某个表单页面。
    2. 服务端生成一个Token,放在用户的Session中,或者浏览器的Cookie中。
    3. 在页面表单附带上Token参数。
    4. 用户提交请求后, 服务端验证表单中的Token是否与用户Session(或Cookies)中的Token一致,一致为合法请求,不是则非法请求。这个Token的值必须是随机的,不可预测的。由于Token的存在,攻击者无法再构造一个带有合法Token的请求实施CSRF攻击。另外使用Token时应注意Token的保密性,尽量把敏感操作由GET改为POST,以form或AJAX形式提交,避免Token泄露。
    CSRF的Token仅仅用于对抗CSRF攻击。当网站同时存在XSS漏洞时候,那这个方案也是空谈。所以XSS带来的问题,应该使用XSS的防御方案予以解决。

    公钥与私钥,http详解

    1.公钥与私钥原理
    1)bob有两把钥匙,一把公钥,另一把私钥

    2)bob把公钥送给他的朋友们-帕蒂,道格,苏珊每人一把 。

    3)苏珊要给bob写一封保密的信。她写完后用bob的公钥加密,就可以达到保密的效果。

    4)bob收信后,用私钥解密,就看到信件内容,这里要强调的是,只要bob的私钥不泄露,这封信就是安全的,即使落在别人手里,也无法解密。

    5)bob给苏珊回信,决定采用“数字签名”。他写完后先用hash函数,生成信件的摘要(digest)。

    6)然后,bob使用私钥,对这个摘要加密,生成“数字签名”(signature)。

    7)bob将这个签名,附在信件下面,一起发给苏珊。

    8)苏珊收信后,取下数字签名,用bob的公钥解密,得到信件的摘要,由此证明,这封信确实是bob发出的

    9)苏珊再对信件本身使用hash函数,将得到的结果,与上一步得到的摘要进行对比,如果两者一致,就证明这封信未被修改过

    10)复杂的情况出现了。道格想欺骗苏珊,他偷偷使用了苏珊的电脑,用自己的公钥换走了鲍勃的公钥。此时,苏珊实际拥有的是道格的公钥,但是还以为这是鲍勃的公钥。因此,道格就可以冒充鲍勃,用自己的私钥做成”数字签名”,写信给苏珊,让苏珊用假的鲍勃公钥进行解密。

    11)后来,苏珊感觉不对劲,发现自己无法确定公钥是否真的属于鲍勃。她想到了一个办法,要求鲍勃去找”证书中心”(certificate authority,简称CA),为公钥做认证。证书中心用自己的私钥,对鲍勃的公钥和一些相关信息一起加密,生成”数字证书”(Digital Certificate)。

    12)bob拿到数字证书后,就可以放心了。以后再给苏珊写信,只要在签名的同时,再附上数字证书就行了。

    13)苏珊收信后,用CA的公钥解开数字证书,就可以拿到bob真实的公钥了,然后就能证明“数字签名”是否真的是bob签的。

    2.https详解
    http协议的网站容易被篡改和劫持,如一些不良运营商会通过代理服务器在你的页面中植入广告等。因此很多网站选择使用https协议。https协议通过TLS层和证书机制提供了内容加密,身份认证,数据完整性三大功能。
    1)下面,我们看一个应用”数字证书”的实例:https协议。这个协议主要用于网页加密。

    2)首先,客户端向服务器发出加密请求。

    3) 服务器用自己的私钥加密网页以后,连同本身的数字证书,一起发送给客户端。

    4)客户端(浏览器)的”证书管理器”,有”受信任的根证书颁发机构”列表。客户端会根据这张列表,查看解开数字证书的公钥是否在列表之内。

    5)如果数字证书记载的网址,与你正在浏览的网址不一致,就说明这张证书可能被冒用,浏览器会发出警告。

    6)如果这张数字证书不是由受信任的机构颁发的,浏览器会发出另一种警告

    原文地址:http://www.youdzone.com/signature.html