HTTP

*这一周匆匆忙忙的研究了HTTP,所有我学到的内容都整理在下面了

 

客户端浏览器:IE、Chrome、Firefox

Web服务器:Apache、IIS

中间传输的协议:HTTP超文本传输协议

协议传的数据:HTML超文本标记语言(5.0)

 

URI:统一资源标识符,抽象

URL:统一资源定位符,是URI的子集,更具体

URL组成:协议、host、请求URI

 

网页安全现状:由于浏览器为了方便客户、抢占市场,而不按标准制作,导致和网页开发者的标准不兼容,从而产生一些安全问题

 

HTTP简介:

HTTP:版本1.0/1.1,1.1是目前最主流,几乎所有的服务器都支持1.0,2.0是HTTPS

  • 必是客户、服务器模型(C/S)
  • 请求必是客户端发出、服务器端回复响应(Request、Response)
    • 请求报文格式:Method、请求URI、协议版本、Request Header(请求首部字段)、空行、内容实体
    • 响应报文格式:协议版本、状态码、状态码的原因短语、Response Header(响应首部字段)、空行、主体
  • HTTP是不保存状态的协议
    • 介绍:HTTP是一种不保存状态、即无状态(stateless)协议。HTTP协议自身不对请求和响应之间的通信状态进行保存。为的是更快地处理大量事物,确保协议的可伸缩性,特意把HTTP协议设计成如此简单的。
    • 如何解决HTTP的无状态问题?
      • 隐含参数Hidden
        • 用的较少,反复复述服务器的话
      • Cookie
        • 用的多
  • HTTP的Method
    • GET  
      • GET可以传变量—在URL传,在URL添加相应的变量和变量值
      • GET请求的内容在浏览器可以看到
      • 得到xxx
      • GET完全无副作用
    • POST
      • 告诉你xxx,还是要给一个结果
      • 动态网页基本上用的都是POST
      • POST的变量在主体里面传,而非URL里,在URL里也看不到
    • PUT:传输文件
      • HTTP/1.1的PUT方法自身不带验证机制,任何人都可以上传文件,存在安全性问题,因此一般的web网站不使用该方法,一般的文件上传仍然用POST
    • HEAD:获得报文首部
      • HEAD方法和GET方法一样,只是不返回报文主体部分。用于确认URI的有效性及资源更新的日期时间等
    • DELETE:删除文件
      • HTTP/1.1的DELETE方法也不带验证机制,所以一般的web网站也不使用该方法,一般删除文件依然采用POST
    • OPTIONS:询问支持的方法
      • OPTIONS方法用来查询针对请求URI指定的资源支持的方法
      • OPTIONS * HTTP/1.1
      • Host:xxx
      • HTTP/1.1 200 OK
      • Allow:GET,POST,HEAD,OPTIONS(返回服务器支持的方法)
    • TRACE:追踪路径
      • 不常用,容易引发XST(Cross-Site Tracing 跨站追踪)攻击
    • CONNECT:要求用隧道协议连接代理
      • CONNECT方法要求在与代理服务器通信时建立隧道,实现用隧道协议进行TCP通信。主要使用SSL(Secure Sockets Layer 安全套接层)和TLS(Transport Layer Security 传输层安全)协议把通信内容加密后经网络隧道传输。
      • CONNECT方法的格式:CONNECT 代理服务器名:端口号 HTTP版本

 

    • GET vs POST
      • 发送的请求符合以下任意一条时—>POST;都不符合—>GET
        1. 请求中包含数据更新等副作用
        2. 发送敏感信息时(防止Referer安全隐患
        3. 发送的信息量很多时(URL长度有限)

副作用:获取资源(内容)以外的其他操作;如追加/更新/删除服务器端的数据、购买商品、注册/删除用户等操作;更新类的页面必须使用POST方法

 

Fiddler:自动做代理proxy(IE&Chrome)

Burpsuite:需要手动做代理

 

debug:调试

decode:解码

encode:编码

 

瞬时协议与解决方案

HTTP1.0是经典的瞬时协议

过程:建立TCP、HTTP请求&HTTP响应、TCP四次挥手

Cisco防火墙:两台,一台挂另一台顶上;需要在两台防火墙之间同步状态化信息,Cisco默认HTTP不同步,其他同步;原因是TCP建立的时候同步,非常有可能同步过去的瞬间,那边已经结束了,就是因为HTTP是瞬时协议

瞬时协议不靠谱:大型网站任何一个页面图片等都需要一次独立的HTTP请求与响应;为了解决这个问题,1.1版本提出了持久连接

持久连接(HTTP Persistent Connections)

也称为HTTP keep-alive/HTTP connection reuse

持久连接的特点是:只要任意一端没有明确提出断开连接,则保持TCP连接状态  

管线化:持久连接使得多数请求以管线化(pipelining)方式发送成为可能。从前发送请求后需等待并收到响应,才能发送下一个请求,管线化技术出现后,不用等待响应亦可直接发送下一个请求;这样就能够做到同时并行发送多个请求,而不需要一个接一个地等待响应了

 

哑服务(如当telnet百度时无响应,要发送Request服务器才会有响应)

当你去访问时无反应,一定要Request才会有反应

 

Cookie技术(解决无状态问题)

HTTP是无状态协议,它不对之前发生过的请求和响应的状态进行管理,也就是说,无法根据之前的状态进行本次的请求处理,HTTP的设计之初就是要尽量的简单、轻量,才能支持更多的并发、请求,但是随着业务需要,需要解决无状态问题

 

Cookie是HTTP附属的

Cookie的工作原理

  1. 请求报文(没有Cookie信息的状态)*首部字段内没有Cookie的相关信息
  2. 响应报文(服务器端生成Cookie信息)
    • <Set-Cookie:sid=1342088372883940; path=/; expires=Wed, >
  3. 请求报文(自动发送保存着的Cookie信息)
    • Cookie:sid=1342088372883940

 

HTTP报文首部

 

HTTP请求报文(客户端发起)

  • HTTP请求行
    • 方法、URI、HTTP版本
  • HTTP首部字段
    • 请求首部字段
    • 通用首部字段
    • 实体首部字段
  • 其他
  • 空行
  • 报文主体

 

HTTP响应报文(服务器响应)

  • 状态行
    • HTTP版本、状态码
  • HTTP首部字段
    • 响应首部字段
    • 通用首部字段
    • 实体首部字段
  • 其他(可能包含HTTP的RFC里未定义的首部(Cookie等))
  • 空行
  • 报文主体

 

编码提升传输速率

HTTP在传输数据时可以按照数据原貌直接传输,也可以在传输过程中通过编码提升传输速率。通过在传输时编码,能有效地处理大量的访问请求。但是编码的操作需要计算机来完成,因此会消耗更多的CPU等资源。

常用的内容编码:

  1. gzip(GNU zip)
  2. compress(UNIX 系统的标准压缩)
  3. deflate(zlib)
  4. identity(不进行编码)

分块传输编码(Chunked Transfer Coding)

 

状态码

200 OK 正常

204 No Content 该状态码代表服务器接收的请求已成功处理,但在返回的响应报文中不含实体的主体部分;也不允许返回任何实体的主体;如当从浏览器发出请求处理后,返回204响应,那么浏览器显示的页面不发生更新;一般在只需要从客户端往服务器发送信息,而对客户端不需要发送新信息内容的情况下使用

206 Partial Content 该状态码表示客户端进行了范围请求,而服务器成功执行了这部分的GET请求,响应报文中包含由Content-Range指定范围的实体内容

 

301 Moved Permanently 永久性重定向,该状态码表示请求的资源已被分配了新的URI,以后应使用资源现在所指的URI。也就是说,如果已经把资源对应的URI保存为书签了,这时应该按Location首部字段提示的URI重新保存

302 303 307 这里没懂,待完善补充

304 Not Modified 没有被修改,该状态码表示客户端发送附带条件的请求A时,服务器端允许请求访问资源,但未满足条件的情况。304状态码返回时,不包含任何响应的主体部分,304虽然被划分在3类中,但是和重定向没有任何关系

重定向通过200OK做,通过html页面的特殊标记META Redirect

<html>

<head>

<title>Meta Redirect临时页面</title>

<meta http-equiv=“refresh” content=“5; URL=http://www.baidu.com”>

</head>

</html>

 

400 Bad Request 错误的请求

401 Unauthorized 未授权的

403 Forbidden 拒绝,权限不够

404 Not Found 请求的资源不存在

 

500 Internal Server Error 程序问题,该状态码表明服务器端在执行请求时发生了错误。也有可能是web应用存在的bug/某些临时的故障

503 Service Unavailable 服务器错误

 

用单台虚拟主机实现多个域名

在相同的IP地址下,由于虚拟主机可以寄存多个不同主机名和域名的web网站,因此在发送HTTP请求时,必须在Host首部内完整指定主机名/域名的URI

 

通信数据转发程序:代理、网关、隧道

使用代理服务器的理由:

  1. 利用缓存技术减少网络带宽的流量
  2. 组织内部针对特定网站的访问控制
  3. 以获取访问日志为主要目的

代理分类:是否使用缓存、是否会修改报文;缓存代理、透明代理/非透明代理

网关:工作机制与代理类似, 网关能使通信线路上的服务器提供非HTTP协议服务;利用网关能提高通信的安全性,因为可以在客户端与网关之间的通信线路上加密以确保连接的安全。如网关可以连接数据库,使用SQL语句查询数据

 

 

HTTP首部字段传递重要信息

HTTP首部字段是构成HTTP报文的要素之一。在客户端与服务器之间以HTTP协议进行通信的过程中,无论是请求还是响应都会使用首部字段,它能起到传递额外重要信息的作用。

使用首部字段是为了给浏览器和服务器提供报文主体大小、所使用的语言、认证信息等内容。

 

HTTP首部字段结构

HTTP首部字段是由首部字段名和字段值构成的,中间用冒号「:」分隔

首部字段名:字段值

 

例如,在HTTP首部中以Content-Type这个字段来表示报文主体的对象类型

Content-Type:text/html

 

另外,字段值对应单个HTTP首部字段可以有多个值

Keep-Alive:timeout=15,max=100

 

通用首部:Cache-Control

通过指定首部字段Cache-Control的指令,就能操作缓存的工作机制。

指令的参数是可选的,多个指令之间通过「,」分隔。首部字段Cache-Control的指令可用于请求及响应时。

Cache-Control:private,max-age=0,no-cache

*不要去缓存页面,我的页面可能刷新很快

Cache-Control:public

明确表明其他用户也可利用缓存

Cache-Control:private

缓存服务器会对该特定用户提供资源缓存的服务,对于其他用户发送过来的请求,代理服务器则不会返回缓存

Cache-Control:no-cache

防止从缓存中返回过期的资源

Request带no-cache,客户端不会接收缓存过的响应—>缓存服务器必须把客户端请求转发给源服务器

Response带no-cache,缓存服务器不能对资源进行缓存

Cache-Control:no-cache=Location

不能使用缓存,无参数值的首部字段可以使用缓存(只能在响应指令中指定该参数)

Cache-Control:no-store

请求和对应的响应/响应中包含机密信息—>不进行缓存

指定缓存期限和认证的指令:

Cache-Control:s-maxage=604800(单位:秒)

s-maxage适用于供多位用户使用的公共缓存服务器,对向同一用户重复返回响应的服务器来说,这个指令没作用;当使用s-maxage指令后,直接忽略对Expires首部字段及max-age指令的处理

Cache-Control:max-age=604800(单位:秒)

当客户端发送的请求中包含max-age指令时,如果判定缓存资源的缓存时间数值比指定时间的数值更小,那么客户端就接收缓存的资源;当max-age的值为0,那么缓存服务器通常需要将请求转发给源服务器

当服务器返回的响应中包含max-age指令时,缓存服务器将不对资源的有效性再作确认,而max-age数值代表资源保存为缓存的最长时间

HTTP/1.1优先处理max-age忽略Expires;HTTP/1.0优先处理Expires而忽略max-age

Cache-Control:min-fresh=60(单位:秒)

要求缓存服务器返回至少还未过指定时间的缓存资源;在60s内如果有超过有效期限的资源都无法作为响应返回了

Cache-Control:max-stale=3600(秒)

使用max-stale可指示缓存资源,即使过期也照常接收

如果指令未指定参数值,那么无论经过多久,客户端都会接收响应;如果指令中指定了具体数值,那么即使过期,只要仍处于max-stale指定的时间内,仍旧会被客户端接收

Cache-Control:only-if-cached

使用only-if-cached指令表示客户端仅在缓存服务器本地缓存目标资源的情况下才会要求其返回;该指令要求缓存服务器不重新加载响应,也不会再次确认资源的有效性;若发生请求缓存服务器的本地缓存无响应,则返回状态码504Gateway Timeout

Cache-Control:must-revalidate

代理会向源服务器再次验证即将返回的响应缓存目前是否仍然有效;若代理无法连通源服务器再次获取有效资源的话,缓存必须给客户端一条504(Gateway Timeout)状态码;使用了must-revalidate指令会忽略请求的max-stale指令,即使已经在首部使用了max-stale,也不会再有效果

Cache-Control:proxy-revalidate

要求所有的缓存服务器在接收到客户端带有该指令的请求返回响应之前,必须再次验证缓存的有效性

Cache-Control:no-transform

使用no-transform指令规定无论是在请求还是响应中,缓存都不能改变实体主体的媒体模型,这样做可以防止缓存或代理压缩图片等类似操作

 

通用首部:Connection

控制代理不再转发的首部字段

  • Connection:不再转发的首部字段名
  • 在客户端发送请求和服务器返回响应内,使用Connection首部字段,可控制不再转发给代理的首部字段

管理持久连接

  • Connection:close
  • HTTP/1.1之前的HTTP版本的默认连接都是非持久连接,若想在旧版本的HTTP协议上维持持续连接,则需要指定Connection首部字段的值为Keep-Alive

 

  • HTTP/1.1版本的默认连接都是持久连接,所以客户端会在持久连接上连续发送请求。当服务器端想明确断开连接时,则指定Connection首部字段的值为Close

 

通用首部:Date

表明创建HTTP报文的日期和时间

 

通用首部:Pragma

HTTP/1.1之前版本的历史遗留字段,仅作为与HTTP/1.0的向后兼容而定义

Pragma:no-cache

该首部字段属于通用首部字段,但只用在客户端发送的请求中,客户端会要求所有的中间服务器不返回缓存的资源

所有的中间服务器如果都能以HTTP/1.1为基准,那直接采用Cache-Control:no-cache指定缓存的处理方式是最为理想的

但要整体掌握全部中间服务器使用的HTTP协议版本却是不现实的,因此,发送的请求会同时含有下面两个首部字段

Cache-Control:no-cache

Pragma:no-cache

 

通用首部:Trailer

首部字段Trailer会事先说明在报文主体后记录了哪些首部字段,该首部字段可应用在HTTP/1.1版本分块传输编码时

 

通用首部:Transfer-Encoding

首部字段Transfer-Encoding规定了传输报文主体时采用的编码方式;HTTP/1.1的传输编码方式仅对分块传输编码有效

Transfer-Encoding:chunked

有效使用分块传输编码,且分别被分成3312字节(cf0为16进制,10进制为3312)和914(392为16进制,10进制为914)字节大小的分块数据

 

通用首部:Upgrade

用于检测HTTP协议及其他协议是否可以使用更高的版本进行通信,其参数值可以用来指定一个完全不同的通信协议

C:

  • GET /index.htm HTTP/1.1
  • Upgrade:TLS/1.0
  • Connection:Upgrade

S:

  • HTTP/1.1 101 Switching Protocols
  • Upgrade:TLS/1.0,HTTP/1.1
  • Connection:Upgrade

首部字段Upgrade指定的值为TLS/1.0,需要注意此处两个字段首部字段的对应关系,Connection的值被指定为Upgrade,Upgrade首部字段产生作用的Upgrade对象仅限于客户端和邻接服务器之间,因此,使用首部字段Upgrade时,还需要额外指定Connection:Upgrade;

对于附有首部字段Upgrade的请求,服务器可用101 Switching Protocols 状态码作为响应返回

 

通用首部:Via

使用首部字段Via

 

  • 通用首部:Warning

与缓存相关;HTTP/1.1的Warning首部是从HTTP/1.0的响应首部(Retry-After)演变过来的;该首部通常会告知用户一些与缓存相关的问题的警告

Warning:[警告码] [警告的主机:端口号] ”[警告内容]” ([日期时间])

 

请求首部:Accept

通知服务器,用户代理能够处理的媒体类型及媒体类型的相对优先级;可以使用type/subtype这种形式,一次指定多种媒体类型

q=0.3表示优先级为0.3比较低,不配的话就是1最高级别;

Accept:text/plain; q=0.3, text/html

 

请求首部:Accept-Charset

通知服务器,用户代理支持的字符集及字符集的相对优先顺序;可以一次性指定多种字符集,与首部字段Accept相同的是可用权重q值来表示相对优先级

 

请求首部:Accept-Language

告知服务器,用户代理能够处理的自然语言集(指中文/英文…)以及自然语言集的相对优先级;可以一次指定多种自然语言集,与首部字段Accept相同的是可用权重q值来表示相对优先级

 

请求首部:Accept-Encoding

用来告知服务器用户代理支持的内容编码及内容编码的优先级顺序;可一次性指定多种内容编码

Accept-Encoding:gzip,deflate

 

请求首部:Host

必须要有的;告知服务器,请求的资源所处的互联网主机名和端口号。Host首部字段在HTTP/1.1规范内是唯一一个必须被包含在请求内的首部字段

 

首部字段Host和以单台服务器分配多个域名的虚拟主机的工作机制有很密切的关联,这是首部字段Host必须存在的意义

对于一个IP一个服务器里面有多个网站的情况,完全通过Host到不同的网站

在首部字段Host中写明网络域名/IP地址

 

请求首部:Authorization

告知服务器,用户代理的认证信息(证书值);通常想要通过服务器认证的用户代理会在接收到返回的401状态码响应后,把首部字段Authorization加入请求中;Authorization:Basic YwRtaw3jfd3s2=

 

请求首部:Referer

首部字段Referer会告知服务器请求的原始资源的URI

客户端一般都会发送Referer首部字段给服务器,但当直接在浏览器的地址栏输入URI,或出于安全性的考虑时,也可以不发送该首部字段

服务器只要查看Referer就能知道请求的URI是从哪个web页面发起的

与get连用会有安全问题,外链的时候泄漏

有些网站防止外链,就是查Referer

 

请求首部:User-Agent

会将创建请求的浏览器和用户代理名称等信息传达给服务器

通过该字段告诉服务器自己的浏览器和系统

服务器识别系统返回不同形式的网页

 

响应首部:Location

使用首部字段Location可以将响应接收方引导至某个与请求URI位置不同的资源

基本上该字段会配合3xx,Redirection的响应,提供重定向的URI

几乎所有的浏览器在接收到包含首部字段Location的响应后,都会强制性地尝试对已提示的重定向资源的访问

 

响应首部:Server

需要修改php和Apache配置信息

修复Server安全问题

/etc/php.ini修改expose_php=Off

/etc/httpd/conf/httpd.conf添加ServerTokens Prod

把php和server信息隐藏

否则会导致严重信息泄露

Server:Apache/2.4.6(CentOS)OpenSSL/1.0.1e-fips PHP/5.4.16

此时版本有漏洞的话就…

 

响应首部:WWW-Authenticate

首部字段WWW-Authenticate用于HTTP访问认证。它会告知客户端适用于访问请求URI所指定资源的认证方案(Basic或是Digest)和带参数提示的质询(challenge);状态码401Unauthorized响应中,肯定带有首部字段WWW-Authenticate

WWW-Authenticate:Basic realm=“Usagidesign Auth”

 

 

 

实体首部:

Allow、

Content-Encoding、

Content-Language、

Content-Length、

Content-Location、

Content-Type、

Expires、

Set-Cookie

通过Allow给客户端回复能够用的method;

Accept-Encoding压缩算法如gzip(正文);

语言;

实体主体部分的大小(单位字节);

回复如Accept-Language的请求,响应值与请求值不一样则首部字段Content-Location内会写明URI;

在ASA防火墙匹配Content-Type做过滤;

超时;

响应的字段

 

Cookie选项

Cookie名字=Cookie值

 

为Cookie服务的首部字段

响应首部字段:Set-Cookie开始状态管理所使用的Cookie信息

请求首部字段:Cookie服务器接收到的Cookie

信息

 

当服务器准备开始管理客户端的状态时,会事先告知各种信息

Set-Cookie:status=enable;expires=Tue, 05 Jul 2011 07:26:31 GMT; =>path=/;domain=.hackr.jp;

 

expires超时选项:当省略expires属性时,其有效期仅限于维持浏览器会话(Session)时间段内;这通常限于浏览器应用程序被关闭之前

 

path路径选项:当指定example.com后,www.example.com/www2.example.com等都可以发送Cookie

不指定domain属性更安全

 

secure属性:用于限制Web页面仅在HTTPS安全连接时,才可以发送Cookie

 

HttpOnly属性:使JavaScript脚本无法获得Cookie;其主要目的为防止跨站脚本攻击(XSS)对Cookie的信息窃取

Set-Cookie=secure;HttpOnly

 

PHP系统自动设置安全属性

修改/etc/php.ini让php自动生成secure和httponly选项

在php.ini中修改如下内容即可

session.cookie_secure = on

session.cookie_httponly = on

*如果启用只能是https,不支持http;可能对于很多网站不合适不匹配

PHP手工产生带安全特性的Token(也是一种Cookie、和PHPSESSID并列,但是多了安全保障),Token的Cookie只能通过HTTPS发给服务器,PHPSESSID则没太多的安全限制

 

HTTP缺点

  1. 通信明文不加密,内容可能被窃听
  2. 不验证通信方的身份,因此有可能遭遇伪装
  3. 无法证明报文的完整性,所以有可能已遭篡改

 

HTTP+加密+认证+完整性保护=HTTPS

一般情况:客户使用证书来验证服务器、服务器使用WEB表单(账号口令)认证客户

 

HTTP加了一个SSL的壳,HTTP over SSL;现在用的是TLS

SSL还加密Email、SMTP、POP3、IMAP

 

SSL:是一个不依赖于平台和应用程序的协议,用于保障TCP-based运用安全,SSL在TCP和应用层之间,会话层安全

 

SSL、IPSec、MACSec、加密机

 

SSL建立的两大阶段

一:握手阶段Handshake phase

  1. 协商加密算法
  2. 认证服务器
  3. 建立用于加密和MAC(Message Authentication Code)用的密钥

(类似于IPSec VPN ISAKMP的作用)

 

二:安全的数据传输阶段Secure data transfer phase

在已经建立的SSL连接里安全的传输数据

(类似于IPSec VPN ESP的作用)

 

SSL三大协议

协商阶段:IP TCP RP HP

传输数据:IP TCP RP APP/DATA

Record Protocol:记录协议是主要的封装协议,它传输不同的高层协议和应用层数据;它从上层用户协议获取信息并且传输,执行需要的任务,例如:分片、压缩、运用MAC和加密,并且传输最终数据;它也执行反向行为,解密、确认、解压缩和重组装来获取数据。

记录协议包括四个上层客户协议,Handshake Protocol握手协议、Alert Protocol告警协议、Change Cipher Spec Protocol修改密钥说明协议、Application Data Protocol应用层数据协议

 

握手协议:Handshake Protocols;握手协议负责建立和恢复SSL会话;由三个子协议组成

  1. Handshake Protocol握手协议协商SSL会话的安全参数
  2. Alert Protocol告警协议,是一个事务管理协议,用于在SSL对等体间传递告警信息,告警信息包括:errors(错误)、exception conditions(异常状况,如错误的MAC/解密失败)、notification(通告,如会话终止)
  3. Change Cipher Spec Protocol修改密钥说明协议,用于在后续记录中通告密钥策略转换

 

Application Data protocol应用层数据协议

 

 

 

 

HTTP使用的认证方式

  • BASIC认证(基本认证)
    • Authorization:Basic YwRtaw3jfd3s2=
  • DIGEST认证(摘要认证)
    • 用哈希值
  • SSL客户端认证
  • FormBase认证(基于表单认证(用户名口令))

 

WEB认证主要采用表单认证,表单是基于网站自己的设计,没有标准

 

此外,还有Windows统一认证(Keberos认证、NTLM认证)

 

Session管理及Cookie

一般使用Cookie来管理Session(会话)

基于表单认证本身是通过服务器端的Web应用,将客户端发送过来的用户ID和密码与之前登录过的信息做匹配来进行认证的

但是HTTP是无状态的,之前已经认证成功的用户状态无法通过协议层面保存下来;无法实现状态管理,因此即使当该用户下一次继续访问, 也无法区分他与其他的用户,于是用Cookie

来管理Session,弥补HTTP协议中不存在的状态管理功能

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 黑客帝国 设计师:白松林 返回首页