笔试面试知识整理

当前文档 《笔试面试知识整理》 由 进击的皇虫 使用 书栈(BookStack.CN) 进行构建,生成于 2018-03-24。
展开查看详情

1. 目 录 致谢 介绍 计算机网络 HTTP 协议 TCP 协议 UDP 协议 IP 协议 Socket 编程 数据结构与算法 链表 树 哈希表 排序 随机 贪心 动态规划 体系结构与操作系统 体系结构基础 操作系统基础 并发技术 内存管理 磁盘与文件 数据库系统 事务处理 索引 编译原理 编译器架构 设计模式 面向对象基础 版本控制 Git SVN iOS 开发 本文档使用 书栈(BookStack.CN) 构建 - 1 -

2. Objective-C 语言基础 类与对象 Block 编程 Objective-C Runtime Objective-C 内存管理 Runloop Cocoa Touch 事件处理 UIApplication UIView UIViewController 动画 网络编程 并发编程 文件系统 设计模式 性能 Swift 类与对象 结构体与枚举 函数与闭包 面试问题 类 参考资料 更多资料 Android 开发 Java 基础 面试问题 Android 基础 Android 系统架构 Activity/Service 生命周期 Android 中的动画(补帧与逐帧) Activity 的 4 种启动模式 ListView原理与优化 本文档使用 书栈(BookStack.CN) 构建 - 2 -

3. Android 中的 Thread, Looper 和 Handler 机制 面试问题 本文档使用 书栈(BookStack.CN) 构建 - 3 -

4.致谢 致谢 当前文档 《笔试面试知识整理》 由 进击的皇虫 使用 书栈(BookStack.CN) 进行构建,生 成于 2018-03-24。 书栈(BookStack.CN) 仅提供文档编写、整理、归类等功能,以及对文档内容的生成和导出工 具。 文档内容由网友们编写和整理,书栈(BookStack.CN) 难以确认文档内容知识点是否错漏。如 果您在阅读文档获取知识的时候,发现文档内容有不恰当的地方,请向我们反馈,让我们共同携手, 将知识准确、高效且有效地传递给每一个人。 同时,如果您在日常生活、工作和学习中遇到有价值有营养的知识文档,欢迎分享到 书栈 (BookStack.CN) ,为知识的传承献上您的一份力量! 如果当前文档生成时间太久,请到 书栈(BookStack.CN) 获取最新的文档,以跟上知识更新换 代的步伐。 文档地址:http://www.bookstack.cn/books/interview_1 书栈官网:http://www.bookstack.cn 书栈开源:https://github.com/TruthHun 分享,让知识传承更久远! 感谢知识的创造者,感谢知识的分享者,也感谢每一位阅读到此处的 读者,因为我们都将成为知识的传承者。 本文档使用 书栈(BookStack.CN) 构建 - 4 -

5.介绍 介绍 笔试面试知识整理 在线阅读 编辑流程 贡献者: 笔试面试知识整理 build passing 在线阅读 本文档使用 Gitbook 制作,在线阅读地址。 所有引用内容版权归原作者所有。 使用 知识共享“署名-非商业性使用-相同方式共享 3.0 中国大陆”许可协议 授权。 编辑流程 首先请安装 Gitbook 并参考其文档进行编辑 完成编辑之后,可以执行 ./serve.sh ,在浏览器中即时预览结果 随时欢迎 issue 和 PR。只需要更改 master 分支的内容,我会去更新 gh-pages。 贡献者: skyline75489 winlandiano dodola AveryLiu JackAlan 本文档使用 书栈(BookStack.CN) 构建 - 5 -

6.计算机网络 计算机网络 计算机网络 计算机网络 HTTP 协议 TCP 协议 UDP 协议 IP 协议 Socket 编程 本文档使用 书栈(BookStack.CN) 构建 - 6 -

7.HTTP 协议 HTTP 协议 HTTP的特性 HTTP报文 请求报文 POST 提交数据的方式 响应报文 条件 GET 持久连接 Transfer-Encoding HTTP Pipelining(HTTP 管线化) 会话跟踪 跨站攻击 参考资料 HTTP的特性 HTTP构建于TCP/IP协议之上,默认端口号是80 HTTP是无连接无状态的 HTTP报文 请求报文 HTTP 协议是以 ASCII 码传输,建立在 TCP/IP 协议之上的应用层规范。规范把 HTTP 请求分为 三个部分:状态行、请求头、消息主体。类似于下面这样: 1. <method> <request-URL> <version> 2. <headers> 3. 4. <entity-body> HTTP定义了与服务器交互的不同方法,最基本的方法有4种,分别 是 GET , POST , PUT , DELETE 。 URL 全称是资源描述符,我们可以这样认为:一 个 URL 地址,它用于描述一个网络上的资源,而 HTTP 中 的 GET , POST , PUT , DELETE 就对应着对这个资源的查,增,改,删4个操作。 1. GET用于信息获取,而且应该是安全的 和 幂等的。 所谓安全的意味着该操作用于获取信息而非修改信息。换句话说,GET 请求一般不应产生副作 本文档使用 书栈(BookStack.CN) 构建 - 7 -

8.HTTP 协议 用。就是说,它仅仅是获取资源信息,就像数据库查询一样,不会修改,增加数据,不会影响资 源的状态。 幂等的意味着对同一URL的多个请求应该返回同样的结果。 GET请求报文示例: 1. GET /books/?sex=man&name=Professional HTTP/1.1 2. Host: www.example.com 3. User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) 4. Gecko/20050225 Firefox/1.0.1 5. Connection: Keep-Alive 2. POST表示可能修改变服务器上的资源的请求。 1. POST / HTTP/1.1 2. Host: www.example.com 3. User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) 4. Gecko/20050225 Firefox/1.0.1 5. Content-Type: application/x-www-form-urlencoded 6. Content-Length: 40 7. Connection: Keep-Alive 8. 9. sex=man&name=Professional 3. 注意: GET 可提交的数据量受到URL长度的限制,HTTP 协议规范没有对 URL 长度进行限制。这 个限制是特定的浏览器及服务器对它的限制 理论上讲,POST 是没有大小限制的,HTTP 协议规范也没有进行大小限制,出于安全考 虑,服务器软件在实现时会做一定限制 参考上面的报文示例,可以发现 GET 和 POST 数据内容是一模一样的,只是位置不同,一 个在URL里,一个在 HTTP 包的包体里 POST 提交数据的方式 HTTP 协议中规定 POST 提交的数据必须在 body 部分中,但是协议中没有规定数据使用哪种编码 方式或者数据格式。实际上,开发者完全可以自己决定消息主体的格式,只要最后发送的 HTTP 请求 满足上面的格式就可以。 但是,数据发送出去,还要服务端解析成功才有意义。一般服务端语言如 php、python 等,以及它 们的 framework,都内置了自动解析常见数据格式的功能。服务端通常是根据请求头(headers) 中的 Content-Type 字段来获知请求中的消息主体是用何种方式编码,再对主体进行解析。所以说 到 POST 提交数据方案,包含了 Content-Type 和消息主体编码方式两部分。下面就正式开始介 本文档使用 书栈(BookStack.CN) 构建 - 8 -

9.HTTP 协议 绍它们: application/x-www-form-urlencoded 这是最常见的 POST 数据提交方式。浏览器的原生 <form> 表单,如果不设置 enctype 属性, 那么最终就会以 application/x-www-form-urlencoded 方式提交数据。上个小节当中的例子便是使用 了这种提交方式。可以看到 body 当中的内容和 GET 请求是完全相同的。 multipart/form-data 这又是一个常见的 POST 数据提交的方式。我们使用表单上传文件时,必须让 <form> 表单的 enctype 等于 multipart/form-data 。直接来看一个请求示例: 1. POST http://www.example.com HTTP/1.1 2. Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA 3. 4. ------WebKitFormBoundaryrGKCBY7qhFd3TrwA 5. Content-Disposition: form-data; name="text" 6. 7. title 8. ------WebKitFormBoundaryrGKCBY7qhFd3TrwA 9. Content-Disposition: form-data; name="file"; filename="chrome.png" 10. Content-Type: image/png 11. 12. PNG ... content of chrome.png ... 13. ------WebKitFormBoundaryrGKCBY7qhFd3TrwA-- 这个例子稍微复杂点。首先生成了一个 boundary 用于分割不同的字段,为了避免与正文内容重 复,boundary 很长很复杂。然后 Content-Type 里指明了数据是以 multipart/form-data 来编 码,本次请求的 boundary 是什么内容。消息主体里按照字段个数又分为多个结构类似的部分,每 部分都是以 —boundary 开始,紧接着是内容描述信息,然后是回车,最后是字段具体内容(文本或 二进制)。如果传输的是文件,还要包含文件名和文件类型信息。消息主体最后以 —boundary— 标 示结束。关于 multipart/form-data 的详细定义,请前往 RFC1867 查看(或者相对友好一点的 MDN 文档)。 这种方式一般用来上传文件,各大服务端语言对它也有着良好的支持。 上面提到的这两种 POST 数据的方式,都是浏览器原生支持的,而且现阶段标准中原生 <form> 表单也只支持这两种方式(通过 <form> 元素的 enctype 属性指定,默认为 application/x- www-form-urlencoded 。其实 enctype 还支持 text/plain,不过用得非常少)。 随着越来越多的 Web 站点,尤其是 WebApp,全部使用 Ajax 进行数据交互之后,我们完全可以 定义新的数据提交方式,例如 application/json , text/xml ,乃至 application/x-protobuf 这种二进制格式,只要服务器可以根据 Content-Type 和 Content-Encoding 正确地解析出请 求,都是没有问题的。 本文档使用 书栈(BookStack.CN) 构建 - 9 -

10.HTTP 协议 响应报文 HTTP 响应与 HTTP 请求相似,HTTP响应也由3个部分构成,分别是: 状态行 响应头(Response Header) 响应正文 状态行由协议版本、数字形式的状态代码、及相应的状态描述,各元素之间以空格分隔。 常见的状态码有如下几种: 200 OK 客户端请求成功 301 Moved Permanently 请求永久重定向 302 Moved Temporarily 请求临时重定向 304 Not Modified 文件未修改,可以直接使用缓存的文件。 400 Bad Request 由于客户端请求有语法错误,不能被服务器所理解。 401 Unauthorized 请求未经授权。这个状态代码必须和WWW-Authenticate报头域一起使用 403 Forbidden 服务器收到请求,但是拒绝提供服务。服务器通常会在响应正文中给出不提供服 务的原因 404 Not Found 请求的资源不存在,例如,输入了错误的URL 500 Internal Server Error 服务器发生不可预期的错误,导致无法完成客户端的请求。 503 Service Unavailable 服务器当前不能够处理客户端的请求,在一段时间之后,服务器可能会 恢复正常。 下面是一个HTTP响应的例子: 1. HTTP/1.1 200 OK 2. 3. Server:Apache Tomcat/5.0.12 4. Date:Mon,6Oct2003 13:23:42 GMT 5. Content-Length:112 6. 7. <html>... 条件 GET HTTP 条件 GET 是 HTTP 协议为了减少不必要的带宽浪费,提出的一种方案。详见 RFC2616 。 1. HTTP 条件 GET 使用的时机? 客户端之前已经访问过某网站,并打算再次访问该网站。 2. HTTP 条件 GET 使用的方法? 本文档使用 书栈(BookStack.CN) 构建 - 10 -

11.HTTP 协议 客户端向服务器发送一个包询问是否在上一次访问网站的时间后是否更改了页面,如果服务器没 有更新,显然不需要把整个网页传给客户端,客户端只要使用本地缓存即可,如果服务器对照客 户端给出的时间已经更新了客户端请求的网页,则发送这个更新了的网页给用户。 下面是一个具体的发送接受报文示例: 客户端发送请求: 1. GET / HTTP/1.1 2. Host: www.sina.com.cn:80 3. If-Modified-Since:Thu, 4 Feb 2010 20:39:13 GMT 4. Connection: Close 第一次请求时,服务器端返回请求数据,之后的请求,服务器根据请求中的 If-Modified-Since 字段判断响应文件没有更新,如果没有更新,服务器返回一个 304 Not Modified 响应,告诉浏 览器请求的资源在浏览器上没有更新,可以使用已缓存的上次获取的文件。 1. HTTP/1.0 304 Not Modified 2. Date: Thu, 04 Feb 2010 12:38:41 GMT 3. Content-Type: text/html 4. Expires: Thu, 04 Feb 2010 12:39:41 GMT 5. Last-Modified: Thu, 04 Feb 2010 12:29:04 GMT 6. Age: 28 7. X-Cache: HIT from sy32-21.sina.com.cn 8. Connection: close 如果服务器端资源已经更新的话,就返回正常的响应。 持久连接 我们知道 HTTP 协议采用“请求-应答”模式,当使用普通模式,即非 Keep-Alive 模式时,每个请 求/应答客户和服务器都要新建一个连接,完成之后立即断开连接(HTTP 协议为无连接的协议);当 使用 Keep-Alive 模式(又称持久连接、连接重用)时,Keep-Alive 功能使客户端到服务器端的 连接持续有效,当出现对服务器的后继请求时,Keep-Alive 功能避免了建立或者重新建立连接。 在 HTTP 1.0 版本中,并没有官方的标准来规定 Keep-Alive 如何工作,因此实际上它是被附加 到 HTTP 1.0协议上,如果客户端浏览器支持 Keep-Alive ,那么就在HTTP请求头中添加一个字 段 Connection: Keep-Alive,当服务器收到附带有 Connection: Keep-Alive 的请求时, 它也会在响应头中添加一个同样的字段来使用 Keep-Alive 。这样一来,客户端和服务器之间的 HTTP连接就会被保持,不会断开(超过 Keep-Alive 规定的时间,意外断电等情况除外),当客户 端发送另外一个请求时,就使用这条已经建立的连接。 在 HTTP 1.1 版本中,默认情况下所有连接都被保持,如果加入 “Connection: close” 才关 本文档使用 书栈(BookStack.CN) 构建 - 11 -

12.HTTP 协议 闭。目前大部分浏览器都使用 HTTP 1.1 协议,也就是说默认都会发起 Keep-Alive 的连接请求 了,所以是否能完成一个完整的 Keep-Alive 连接就看服务器设置情况。 由于 HTTP 1.0 没有官方的 Keep-Alive 规范,并且也已经基本被淘汰,以下讨论均是针对 HTTP 1.1 标准中的 Keep-Alive 展开的。 注意: HTTP Keep-Alive 简单说就是保持当前的TCP连接,避免了重新建立连接。 HTTP 长连接不可能一直保持,例如 Keep-Alive: timeout=5, max=100 ,表示这个TCP通道可以 保持5秒,max=100,表示这个长连接最多接收100次请求就断开。 HTTP 是一个无状态协议,这意味着每个请求都是独立的,Keep-Alive 没能改变这个结果。另 外,Keep-Alive也不能保证客户端和服务器之间的连接一定是活跃的,在 HTTP1.1 版本中也 如此。唯一能保证的就是当连接被关闭时你能得到一个通知,所以不应该让程序依赖于 Keep- Alive 的保持连接特性,否则会有意想不到的后果。 使用长连接之后,客户端、服务端怎么知道本次传输结束呢?两部分:1. 判断传输数据是否达 到了Content-Length 指示的大小;2. 动态生成的文件没有 Content-Length ,它是分块 传输(chunked),这时候就要根据 chunked 编码来判断,chunked 编码的数据在最后有一 个空 chunked 块,表明本次传输数据结束,详见这里。什么是 chunked 分块传输呢?下面 我们就来介绍一下。 Transfer-Encoding Transfer-Encoding 是一个用来标示 HTTP 报文传输格式的头部值。尽管这个取值理论上可以有 很多,但是当前的 HTTP 规范里实际上只定义了一种传输取值——chunked。 如果一个HTTP消息(请求消息或应答消息)的Transfer-Encoding消息头的值为chunked,那么, 消息体由数量未定的块组成,并以最后一个大小为0的块为结束。 每一个非空的块都以该块包含数据的字节数(字节数以十六进制表示)开始,跟随一个CRLF (回车 及换行),然后是数据本身,最后块CRLF结束。在一些实现中,块大小和CRLF之间填充有白空格 (0x20)。 最后一块是单行,由块大小(0),一些可选的填充白空格,以及CRLF。最后一块不再包含任何数 据,但是可以发送可选的尾部,包括消息头字段。消息最后以CRLF结尾。 一个示例响应如下: 1. HTTP/1.1 200 OK 2. Content-Type: text/plain 3. Transfer-Encoding: chunked 4. 本文档使用 书栈(BookStack.CN) 构建 - 12 -

13.HTTP 协议 5. 25 6. This is the data in the first chunk 7. 8. 1A 9. and this is the second one 10. 0 注意: chunked 和 multipart 两个名词在意义上有类似的地方,不过在 HTTP 协议当中这两个概 念则不是一个类别的。multipart 是一种 Content-Type,标示 HTTP 报文内容的类型,而 chunked 是一种传输格式,标示报头将以何种方式进行传输。 chunked 传输不能事先知道内容的长度,只能靠最后的空 chunk 块来判断,因此对于下载请 求来说,是没有办法实现进度的。在浏览器和下载工具中,偶尔我们也会看到有些文件是看不到 下载进度的,即采用 chunked 方式进行下载。 chunked 的优势在于,服务器端可以边生成内容边发送,无需事先生成全部的内容。HTTP/2 不支持 Transfer-Encoding: chunked,因为 HTTP/2 有自己的 streaming 传输方式。 HTTP Pipelining(HTTP 管线化) 默认情况下 HTTP 协议中每个传输层连接只能承载一个 HTTP 请求和响应,浏览器会在收到上一个 请求的响应之后,再发送下一个请求。在使用持久连接的情况下,某个连接上消息的传递类似于 请求1 -> 响应1 -> 请求2 -> 响应2 -> 请求3 -> 响应3 。 HTTP Pipelining(管线化)是将多个 HTTP 请求整批提交的技术,在传送过程中不需等待服务端 的回应。使用 HTTP Pipelining 技术之后,某个连接上的消息变成了类似这样 请求1 -> 请求2 -> 请求3 -> 响应1 -> 响应2 -> 响应3 。 注意下面几点: 管线化机制通过持久连接(persistent connection)完成,仅 HTTP/1.1 支持此技术 (HTTP/1.0不支持) 只有 GET 和 HEAD 请求可以进行管线化,而 POST 则有所限制 初次创建连接时不应启动管线机制,因为对方(服务器)不一定支持 HTTP/1.1 版本的协议 管线化不会影响响应到来的顺序,如上面的例子所示,响应返回的顺序并未改变 HTTP /1.1 要求服务器端支持管线化,但并不要求服务器端也对响应进行管线化处理,只是要 求对于管线化的请求不失败即可 由于上面提到的服务器端问题,开启管线化很可能并不会带来大幅度的性能提升,而且很多服务 器端和代理程序对管线化的支持并不好,因此现代浏览器如 Chrome 和 Firefox 默认并未开 启管线化支持 更多关于 HTTP Pipelining 的知识可以参考这里。 本文档使用 书栈(BookStack.CN) 构建 - 13 -

14.HTTP 协议 会话跟踪 1. 什么是会话? 客户端打开与服务器的连接发出请求到服务器响应客户端请求的全过程称之为会话。 2. 什么是会话跟踪? 会话跟踪指的是对同一个用户对服务器的连续的请求和接受响应的监视。 3. 为什么需要会话跟踪? 浏览器与服务器之间的通信是通过HTTP协议进行通信的,而HTTP协议是”无状态”的协议,它不 能保存客户的信息,即一次响应完成之后连接就断开了,下一次的请求需要重新连接,这样就需 要判断是否是同一个用户,所以才有会话跟踪技术来实现这种要求。 1. 会话跟踪常用的方法: i. URL重写 URL(统一资源定位符)是Web上特定页面的地址,URL重写的技术就是在URL结尾添加一个附 加数据以标识该会话,把会话ID通过URL的信息传递过去,以便在服务器端进行识别不同的用 户。 ii. 隐藏表单域 将会话ID添加到HTML表单元素中提交到服务器,此表单元素并不在客户端显示 iii. Cookie Cookie是Web服务器发送给客户端的一小段信息,客户端请求时可以读取该信息发送到服务 器端,进而进行用户的识别。对于客户端的每次请求,服务器都会将Cookie发送到客户端, 在客户端可以进行保存,以便下次使用。 客户端可以采用两种方式来保存这个Cookie对象,一种方式是保存在客户端内存中,称为临 时Cookie,浏览器关闭后这个Cookie对象将消失。另外一种方式是保存在客户机的磁盘 上,称为永久Cookie。以后客户端只要访问该网站,就会将这个Cookie再次发送到服务器 上,前提是这个Cookie在有效期内,这样就实现了对客户的跟踪。 Cookie是可以被禁止的。 iv. Session: 每一个用户都有一个不同的session,各个用户之间是不能共享的,是每个用户所独享的, 在session中可以存放信息。 本文档使用 书栈(BookStack.CN) 构建 - 14 -

15.HTTP 协议 在服务器端会创建一个session对象,产生一个sessionID来标识这个session对象,然后 将这个sessionID放入到Cookie中发送到客户端,下一次访问时,sessionID会发送到服 务器,在服务器端进行识别不同的用户。 Session的实现依赖于Cookie,如果Cookie被禁用,那么session也将失效。 跨站攻击 CSRF(Cross-site request forgery,跨站请求伪造) CSRF(XSRF) 顾名思义,是伪造请求,冒充用户在站内的正常操作。 例如,一论坛网站的发贴是通过 GET 请求访问,点击发贴之后 JS 把发贴内容拼接成目标 URL 并访问: 1. http://example.com/bbs/create_post.php?title=标题&content=内容 那么,我们只需要在论坛中发一帖,包含一链接: 1. http://example.com/bbs/create_post.php?title=我是脑残&content=哈哈 只要有用户点击了这个链接,那么他们的帐户就会在不知情的情况下发布了这一帖子。可能这只 是个恶作剧,但是既然发贴的请求可以伪造,那么删帖、转帐、改密码、发邮件全都可以伪造。 如何防范 CSRF 攻击?可以注意以下几点: 关键操作只接受POST请求 验证码 CSRF攻击的过程,往往是在用户不知情的情况下构造网络请求。所以如果使用验证码,那么 每次操作都需要用户进行互动,从而简单有效的防御了CSRF攻击。 但是如果你在一个网站作出任何举动都要输入验证码会严重影响用户体验,所以验证码一般 只出现在特殊操作里面,或者在注册时候使用。 检测 Referer 常见的互联网页面与页面之间是存在联系的,比如你在 www.baidu.com 应该是找不到通 往 www.google.com 的链接的,再比如你在论坛留言,那么不管你留言后重定向到哪里去了, 之前的那个网址一定会包含留言的输入框,这个之前的网址就会保留在新页面头文件的 Referer 中 通过检查 Referer 的值,我们就可以判断这个请求是合法的还是非法的,但是问题出在服务 本文档使用 书栈(BookStack.CN) 构建 - 15 -

16.HTTP 协议 器不是任何时候都能接受到 Referer 的值,所以 Referer Check 一般用于监控 CSRF 攻击的发生,而不用来抵御攻击。 Token 目前主流的做法是使用 Token 抵御 CSRF 攻击。下面通过分析 CSRF 攻击来理解为什么 Token 能够有效 CSRF攻击要成功的条件在于攻击者能够预测所有的参数从而构造出合法的请求。所以根据不 可预测性原则,我们可以对参数进行加密从而防止CSRF攻击。 另一个更通用的做法是保持原有参数不变,另外添加一个参数Token,其值是随机的。这样 攻击者因为不知道Token而无法构造出合法的请求进行攻击。 Token 使用原则 Token 要足够随机————只有这样才算不可预测 Token 是一次性的,即每次请求成功后要更新Token————这样可以增加攻击难度,增 加预测难度 Token 要注意保密性————敏感操作使用 post,防止 Token 出现在 URL 中 注意:过滤用户输入的内容不能阻挡 csrf,我们需要做的是过滤请求的来源。 XSS(Cross Site Scripting,跨站脚本攻击) XSS 全称“跨站脚本”,是注入攻击的一种。其特点是不对服务器端造成任何伤害,而是通过一些 正常的站内交互途径,例如发布评论,提交含有 JavaScript 的内容文本。这时服务器端如果 没有过滤或转义掉这些脚本,作为内容发布到了页面上,其他用户访问这个页面的时候就会运行 这些脚本。 运行预期之外的脚本带来的后果有很多中,可能只是简单的恶作剧——一个关不掉的窗口: 1. while (true) { 2. alert("你关不掉我~"); 3. } 也可以是盗号或者其他未授权的操作。 XSS 是实现 CSRF 的诸多途径中的一条,但绝对不是唯一的一条。一般习惯上把通过 XSS 来 实现的 CSRF 称为 XSRF。 如何防御 XSS 攻击? 理论上,所有可输入的地方没有对输入数据进行处理的话,都会存在XSS漏洞,漏洞的危害取决 于攻击代码的威力,攻击代码也不局限于script。防御 XSS 攻击最简单直接的方法,就是过滤 用户的输入。 本文档使用 书栈(BookStack.CN) 构建 - 16 -

17.HTTP 协议 如果不需要用户输入 HTML,可以直接对用户的输入进行 HTML escape 。下面一小段脚本: 1. <script>window.location.href=”http://www.baidu.com”;</script> 经过 escape 之后就成了: 1. &lt;script&gt;window.location.href=&quot;http://www.baidu.com&quot;&lt;/script&gt; 它现在会像普通文本一样显示出来,变得无毒无害,不能执行了。 当我们需要用户输入 HTML 的时候,需要对用户输入的内容做更加小心细致的处理。仅仅粗暴地 去掉 script 标签是没有用的,任何一个合法 HTML 标签都可以添加 onclick 一类的事件属 性来执行 JavaScript。更好的方法可能是,将用户的输入使用 HTML 解析库进行解析,获取 其中的数据。然后根据用户原有的标签属性,重新构建 HTML 元素树。构建的过程中,所有的标 签、属性都只从白名单中拿取。 参考资料 浅谈HTTP中Get与Post的区别 http请求与http响应详细解析 HTTP 条件 Get (Conditional Get) HTTP中的长连接与短连接 HTTP Keep-Alive模式 分块传输编码 HTTP 管线化(HTTP pipelining) HTTP协议及其POST与GET操作差异 & C#中如何使用POST、GET等 四种常见的 POST 提交数据方式 @126/blog/static/11758032520127302714624/">会话跟踪 总结 XSS 与 CSRF 两种跨站攻击 CSRF简单介绍与利用方法 XSS攻击及防御 百度百科:HTTP 本文档使用 书栈(BookStack.CN) 构建 - 17 -

18.TCP 协议 TCP 协议 TCP 的特性 三次握手与四次挥手 SYN攻击 TCP KeepAlive 参考资料 TCP 的特性 TCP 提供一种面向连接的、可靠的字节流服务 在一个 TCP 连接中,仅有两方进行彼此通信。广播和多播不能用于 TCP TCP 使用校验和,确认和重传机制来保证可靠传输 TCP 给数据分节进行排序,并使用累积确认保证数据的顺序不变和非重复 TCP 使用滑动窗口机制来实现流量控制,通过动态改变窗口的大小进行拥塞控制 注意:TCP 并不能保证数据一定会被对方接收到,因为这是不可能的。TCP 能够做到的是,如果有 可能,就把数据递送到接收方,否则就(通过放弃重传并且中断连接这一手段)通知用户。因此准确 说 TCP 也不是 100% 可靠的协议,它所能提供的是数据的可靠递送或故障的可靠通知。 三次握手与四次挥手 所谓三次握手(Three-way Handshake),是指建立一个 TCP 连接时,需要客户端和服务器总共发 送3个包。 三次握手的目的是连接服务器指定端口,建立 TCP 连接,并同步连接双方的序列号和确认号,交换 TCP 窗口大小信息。在 socket 编程中,客户端执行 connect() 时。将触发三次握手。 第一次握手(SYN=1, seq=x): 客户端发送一个 TCP 的 SYN 标志位置1的包,指明客户端打算连接的服务器的端口,以及初始 序号 X,保存在包头的序列号(Sequence Number)字段里。 发送完毕后,客户端进入 SYN_SEND 状态。 第二次握手(SYN=1, ACK=1, seq=y, ACKnum=x+1): 服务器发回确认包(ACK)应答。即 SYN 标志位和 ACK 标志位均为1。服务器端选择自己 ISN 序列号,放到 Seq 域里,同时将确认序号(Acknowledgement Number)设置为客户的 ISN 加1,即X+1。 发送完毕后,服务器端进入 SYN_RCVD 状态。 本文档使用 书栈(BookStack.CN) 构建 - 18 -

19.TCP 协议 第三次握手(ACK=1,ACKnum=y+1) 客户端再次发送确认包(ACK),SYN 标志位为0,ACK 标志位为1,并且把服务器发来 ACK 的 序号字段+1,放在确定字段中发送给对方,并且在数据段放写ISN的+1 发送完毕后,客户端进入 ESTABLISHED 状态,当服务器端接收到这个包时,也进入 ESTABLISHED 状态,TCP 握手结束。 三次握手的过程的示意图如下: TCP 的连接的拆除需要发送四个包,因此称为四次挥手(Four-way handshake),也叫做改进的三 次握手。客户端或服务器均可主动发起挥手动作,在 socket 编程中,任何一方执行 close() 操 作即可产生挥手操作。 第一次挥手(FIN=1,seq=x) 假设客户端想要关闭连接,客户端发送一个 FIN 标志位置为1的包,表示自己已经没有数据可以 发送了,但是仍然可以接受数据。 发送完毕后,客户端进入 FIN_WAIT_1 状态。 第二次挥手(ACK=1,ACKnum=x+1) 服务器端确认客户端的 FIN 包,发送一个确认包,表明自己接受到了客户端关闭连接的请求, 但还没有准备好关闭连接。 发送完毕后,服务器端进入 CLOSE_WAIT 状态,客户端接收到这个确认包之后,进入 FIN_WAIT_2 状态,等待服务器端关闭连接。 本文档使用 书栈(BookStack.CN) 构建 - 19 -

20.TCP 协议 第三次挥手(FIN=1,seq=y) 服务器端准备好关闭连接时,向客户端发送结束连接请求,FIN 置为1。 发送完毕后,服务器端进入 LAST_ACK 状态,等待来自客户端的最后一个ACK。 第四次挥手(ACK=1,ACKnum=y+1) 客户端接收到来自服务器端的关闭请求,发送一个确认包,并进入 TIME_WAIT 状态,等待可能 出现的要求重传的 ACK 包。 服务器端接收到这个确认包之后,关闭连接,进入 CLOSED 状态。 客户端等待了某个固定时间(两个最大段生命周期,2MSL,2 Maximum Segment Lifetime)之后,没有收到服务器端的 ACK ,认为服务器端已经正常关闭连接,于是自己也 关闭连接,进入 CLOSED 状态。 四次挥手的示意图如下: SYN攻击 什么是 SYN 攻击(SYN Flood)? 在三次握手过程中,服务器发送 SYN-ACK 之后,收到客户端的 ACK 之前的 TCP 连接称为半 连接(half-open connect)。此时服务器处于 SYN_RCVD 状态。当收到 ACK 后,服务器才 能转入 ESTABLISHED 状态. 本文档使用 书栈(BookStack.CN) 构建 - 20 -

21.TCP 协议 SYN 攻击指的是,攻击客户端在短时间内伪造大量不存在的IP地址,向服务器不断地发送SYN 包,服务器回复确认包,并等待客户的确认。由于源地址是不存在的,服务器需要不断的重发直 至超时,这些伪造的SYN包将长时间占用未连接队列,正常的SYN请求被丢弃,导致目标系统运行 缓慢,严重者会引起网络堵塞甚至系统瘫痪。 SYN 攻击是一种典型的 DoS/DDoS 攻击。 如何检测 SYN 攻击? 检测 SYN 攻击非常的方便,当你在服务器上看到大量的半连接状态时,特别是源IP地址是随机 的,基本上可以断定这是一次SYN攻击。在 Linux/Unix 上可以使用系统自带的 netstats 命令来检测 SYN 攻击。 如何防御 SYN 攻击? SYN攻击不能完全被阻止,除非将TCP协议重新设计。我们所做的是尽可能的减轻SYN攻击的危 害,常见的防御 SYN 攻击的方法有如下几种: 缩短超时(SYN Timeout)时间 增加最大半连接数 过滤网关防护 SYN cookies技术 TCP KeepAlive TCP 的连接,实际上是一种纯软件层面的概念,在物理层面并没有“连接”这种概念。TCP 通信双方 建立交互的连接,但是并不是一直存在数据交互,有些连接会在数据交互完毕后,主动释放连接,而 有些不会。在长时间无数据交互的时间段内,交互双方都有可能出现掉电、死机、异常重启等各种意 外,当这些意外发生之后,这些 TCP 连接并未来得及正常释放,在软件层面上,连接的另一方并不 知道对端的情况,它会一直维护这个连接,长时间的积累会导致非常多的半打开连接,造成端系统资 源的消耗和浪费,为了解决这个问题,在传输层可以利用 TCP 的 KeepAlive 机制实现来实现。主 流的操作系统基本都在内核里支持了这个特性。 TCP KeepAlive 的基本原理是,隔一段时间给连接对端发送一个探测包,如果收到对方回应的 ACK,则认为连接还是存活的,在超过一定重试次数之后还是没有收到对方的回应,则丢弃该 TCP 连接。 TCP-Keepalive-HOWTO 有对 TCP KeepAlive 特性的详细介绍,有兴趣的同学可以参考。这里 主要说一下,TCP KeepAlive 的局限。首先 TCP KeepAlive 监测的方式是发送一个 probe 包,会给网络带来额外的流量,另外 TCP KeepAlive 只能在内核层级监测连接的存活与否,而连 接的存活不一定代表服务的可用。例如当一个服务器 CPU 进程服务器占用达到 100%,已经卡死不 能响应请求了,此时 TCP KeepAlive 依然会认为连接是存活的。因此 TCP KeepAlive 对于应 用层程序的价值是相对较小的。需要做连接保活的应用层程序,例如 QQ,往往会在应用层实现自己 本文档使用 书栈(BookStack.CN) 构建 - 21 -

22.TCP 协议 的心跳功能。 参考资料 计算机网络:自顶向下方法 TCP三次握手及四次挥手详细图解 TCP协议三次握手过程分析 TCP协议中的三次握手和四次挥手(图解) 百度百科:SYN攻击 TCP-Keepalive-HOWTO 本文档使用 书栈(BookStack.CN) 构建 - 22 -

23.UDP 协议 UDP 协议 UDP 简介 UDP 简介 UDP 是一个简单的传输层协议。和 TCP 相比,UDP 有下面几个显著特性: UDP 缺乏可靠性。UDP 本身不提供确认,序列号,超时重传等机制。UDP 数据报可能在网络中 被复制,被重新排序。即 UDP 不保证数据报会到达其最终目的地,也不保证各个数据报的先后 顺序,也不保证每个数据报只到达一次 UDP 数据报是有长度的。每个 UDP 数据报都有长度,如果一个数据报正确地到达目的地,那么 该数据报的长度将随数据一起传递给接收方。而 TCP 是一个字节流协议,没有任何(协议上 的)记录边界。 UDP 是无连接的。UDP 客户和服务器之前不必存在长期的关系。UDP 发送数据报之前也不需要 经过握手创建连接的过程。 UDP 支持多播和广播。 本文档使用 书栈(BookStack.CN) 构建 - 23 -

24.IP 协议 IP 协议 IP 协议简介 IP 地址的分类 A类地址 B类地址 C类地址 D 类地址 广播与多播 BGP 参考资料 IP 协议简介 IP 协议位于 TCP/IP 协议的第三层——网络层。与传输层协议相比,网络层的责任是提供点到点 (hop by hop)的服务,而传输层(TCP/UDP)则提供端到端(end to end)的服务。 IP 地址的分类 A类地址 B类地址 C类地址 D 类地址 广播与多播 广播和多播仅用于UDP(TCP是面向连接的)。 广播 一共有四种广播地址: i. 受限的广播 受限的广播地址为255.255.255.255。该地址用于主机配置过程中IP数据报的目的地址, 本文档使用 书栈(BookStack.CN) 构建 - 24 -

25.IP 协议 在任何情况下,router不转发目的地址为255.255.255.255的数据报,这样的数据报仅出 现在本地网络中。 ii. 指向网络的广播 指向网络的广播地址是主机号为全1的地址。A类网络广播地址为netid.255.255.255,其 中netid为A类网络的网络号。 一个router必须转发指向网络的广播,但它也必须有一个不进行转发的选择。 iii. 指向子网的广播 指向子网的广播地址为主机号为全1且有特定子网号的地址。作为子网直接广播地址的IP地 址需要了解子网的掩码。例如,router收到128.1.2.255的数据报,当B类网路128.1的子 网掩码为255.255.255.0时,该地址就是指向子网的广播地址;但是如果子网掩码为 255.255.254.0,该地址就不是指向子网的广播地址。 iv. 指向所有子网的广播 指向所有子网的广播也需要了解目的网络的子网掩码,以便与指向网络的广播地址区分开 来。指向所有子网的广播地址的子网号和主机号为全1.例如,如果子网掩码为 255.255.255.0,那么128.1.255.255就是一个指向所有子网的广播地址。 当前的看法是这种广播是陈旧过时的,更好的方式是使用多播而不是对所有子网的广播。 广播示例: PING 192.168.0.255 (192.168.0.255): 56 data bytes 64 bytes from 192.168.0.107: icmp_seq=0 ttl=64 time=0.199 ms 64 bytes from 192.168.0.106: icmp_seq=0 ttl=64 time=45.357 ms 64 bytes from 192.168.0.107: icmp_seq=1 ttl=64 time=0.203 ms 64 bytes from 192.168.0.106: icmp_seq=1 ttl=64 time=269.475 ms 64 bytes from 192.168.0.107: icmp_seq=2 ttl=64 time=0.102 ms 64 bytes from 192.168.0.106: icmp_seq=2 ttl=64 time=189.881 ms 可以看到的确收到了来自两个主机的答复,其中 192.168.0.107 是本机地址。 多播 多播又叫组播,使用D类地址,D类地址分配的28bit均用作多播组号而不再表示其他。 多播组地址包括1110的最高4bit和多播组号。它们通常可以表示为点分十进制数,范围从 224.0.0.0到239.255.255.255。 多播的出现减少了对应用不感兴趣主机的处理负荷。 多播的特点: 本文档使用 书栈(BookStack.CN) 构建 - 25 -

26.IP 协议 允许一个或多个发送者(组播源)发送单一的数据包到多个接收者(一次的,同时的)的网 络技术 可以大大的节省网络带宽,因为无论有多少个目标地址,在整个网络的任何一条链路上只传 送单一的数据包 多播技术的核心就是针对如何节约网络资源的前提下保证服务质量。 1. 多播示例: 2. 3. PING 224.0.0.1 (224.0.0.1): 56 data bytes 4. 64 bytes from 192.168.0.107: icmp_seq=0 ttl=64 time=0.081 ms 5. 64 bytes from 192.168.0.106: icmp_seq=0 ttl=64 time=123.081 ms 6. 64 bytes from 192.168.0.107: icmp_seq=1 ttl=64 time=0.122 ms 7. 64 bytes from 192.168.0.106: icmp_seq=1 ttl=64 time=67.312 ms 8. 64 bytes from 192.168.0.107: icmp_seq=2 ttl=64 time=0.132 ms 9. 64 bytes from 192.168.0.106: icmp_seq=2 ttl=64 time=447.073 ms 10. 64 bytes from 192.168.0.107: icmp_seq=3 ttl=64 time=0.132 ms 11. 64 bytes from 192.168.0.106: icmp_seq=3 ttl=64 time=188.800 ms BGP 边界网关协议(BGP)是运行于 TCP 上的一种自治系统的路由协议 BGP 是唯一一个用来处理像因特网大小的网络的协议,也是唯一能够妥善处理好不相关路由域间 的多路连接的协议 BGP是一种外部网关协议(Exterior Gateway Protocol,EGP),与OSPF、RIP等内部网关 协议(Interior Gateway Protocol,IGP)不同,BGP不在于发现和计算路由,而在于控制 路由的传播和选择最佳路由 BGP使用TCP作为其传输层协议(端口号179),提高了协议的可靠性 BGP既不是纯粹的矢量距离协议,也不是纯粹的链路状态协议 BGP支持CIDR(Classless Inter-Domain Routing,无类别域间路由) 路由更新时,BGP只发送更新的路由,大大减少了BGP传播路由所占用的带宽,适用于在 Internet上传播大量的路由信息 BGP路由通过携带AS路径信息彻底解决路由环路问题 BGP提供了丰富的路由策略,能够对路由实现灵活的过滤和选择 BGP易于扩展,能够适应网络新的发展 本文档使用 书栈(BookStack.CN) 构建 - 26 -

27.IP 协议 参考资料 多播与广播 TCP_IP:广播和多播 百度百科:BGP 本文档使用 书栈(BookStack.CN) 构建 - 27 -

28.Socket 编程 Socket 编程 Socket 基本概念 写一个简易的 WebServer 参考资料 Socket 基本概念 Socket 是对 TCP/IP 协议族的一种封装,是应用层与TCP/IP协议族通信的中间软件抽象层。从设 计模式的角度看来,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口 后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。 Socket 还可以认为是一种网络间不同计算机上的进程通信的一种方法,利用三元组(ip地址,协 议,端口)就可以唯一标识网络中的进程,网络中的进程通信可以利用这个标志与其它进程进行交 互。 Socket 起源于 Unix ,Unix/Linux 基本哲学之一就是“一切皆文件”,都可以用“打开(open) –> 读写(write/read) –> 关闭(close)”模式来进行操作。因此 Socket 也被处理为一种特殊 的文件。 写一个简易的 WebServer 一个简易的 Server 的流程如下: 1.建立连接,接受一个客户端连接。 2.接受请求,从网络中读取一条 HTTP 请求报文。 3.处理请求,访问资源。 4.构建响应,创建带有 header 的 HTTP 响应报文。 5.发送响应,传给客户端。 省略流程 3,大体的程序与调用的函数逻辑如下: socket() 创建套接字 bind() 分配套接字地址 listen() 等待连接请求 accept() 允许连接请求 read()/write() 数据交换 close() 关闭连接 代码如下: 本文档使用 书栈(BookStack.CN) 构建 - 28 -

29.Socket 编程 1. #include <cstdio> 2. #include <cstdlib> 3. #include <cstring> 4. #include <unistd.h> 5. #include <sys/socket.h> 6. #include <arpa/inet.h> 7. #include <string> 8. #include <cstring> 9. #include <iostream> 10. 11. using namespace std; 12. 13. const int port = 9090; 14. const int buffer_size = 1<<20; 15. const int method_size = 1<<10; 16. const int filename_size = 1<<10; 17. const int common_buffer_size = 1<<10; 18. 19. void handleError(const string &message); 20. void requestHandling(int *sock); 21. void sendError(int *sock); 22. void sendData(int *sock, char *filename); 23. void sendHTML(int *sock, char *filename); 24. void sendJPG(int *sock, char *filename); 25. 26. int main() 27. { 28. int server_sock; 29. int client_sock; 30. 31. struct sockaddr_in server_address; 32. struct sockaddr_in client_address; 33. 34. socklen_t client_address_size; 35. 36. server_sock = socket(PF_INET, SOCK_STREAM, 0); 37. 38. if (server_sock == -1) 39. { 40. handleError("socket error"); 41. } 42. 43. memset(&server_address,0,sizeof(server_address)); 44. server_address.sin_family = AF_INET; 45. server_address.sin_addr.s_addr = htonl(INADDR_ANY); 46. server_address.sin_port = htons(port); 47. 48. if(bind(server_sock,(struct sockaddr*)&server_address, sizeof(server_address)) == -1){ 本文档使用 书栈(BookStack.CN) 构建 - 29 -