<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>gsfish's blog</title>
    <description>安全开发 | 代码审计 | 漏洞挖掘 | 渗透测试</description>
    <link>https://www.grassfish.net/</link>
    <atom:link href="https://www.grassfish.net/feed.xml" rel="self" type="application/rss+xml" />
    <pubDate>Mon, 11 Apr 2022 05:23:47 +0000</pubDate>
    <lastBuildDate>Mon, 11 Apr 2022 05:23:47 +0000</lastBuildDate>
    <generator>Jekyll v3.9.0</generator>
    
      <item>
        <title>各种疑难杂症（持续更新）</title>
        <description>&lt;h2 id=&quot;jni-多线程访问共享对象之方案&quot;&gt;JNI 多线程访问共享对象之方案&lt;/h2&gt;

&lt;p&gt;参考资料：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/questions/44420937/how-do-you-properly-synchronize-threads-on-the-native-side-of-a-jni-environment&quot;&gt;How do you properly synchronize threads on the native side of a JNI environment&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.jianshu.com/p/9b83cc5a5ba8&quot;&gt;Android JNI 编程实践&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;elasticsearch-过滤后聚合结果之方案&quot;&gt;ElasticSearch 过滤后聚合结果之方案&lt;/h2&gt;

&lt;p&gt;参考资料：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;https://elasticsearch.cn/question/656&quot;&gt;ElasticSearch 如何先聚合后过滤&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://elasticsearch.cn/question/3581&quot;&gt;es 如何将聚合结果作为条件进行过滤&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;php-报错cant-use-function-return-value-in-write-context&quot;&gt;PHP 报错：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Can't use function return value in write context&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;原因：&lt;/p&gt;

&lt;p&gt;PHP 5.5 以下的版本，只能向 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;empty()&lt;/code&gt; 函数传递变量，不能传递引用（函数等）&lt;/p&gt;

&lt;h2 id=&quot;mysql-客户端连接本地服务器时无法指定端口&quot;&gt;MySQL 客户端连接本地服务器时无法指定端口&lt;/h2&gt;

&lt;p&gt;当目标地址为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;localhost&lt;/code&gt;（默认）时，MySQL 客户端使用 unix socket 进行连接，需改为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;127.0.0.1&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;参考资料：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;https://serverfault.com/questions/306421/why-does-the-mysql-command-line-tool-ignore-the-port-parameter&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;docker-for-windows-无法监听-2375-端口&quot;&gt;Docker for Windows 无法监听 2375 端口&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2375&lt;/code&gt; 在 Windows 的保留范围内，使用前需将其排除&lt;/p&gt;

&lt;p&gt;参考资料：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;https://github.com/docker/for-win/issues/3546&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;windows-安装-mysqlclient-时失败&quot;&gt;Windows 安装 mysqlclient 时失败&lt;/h2&gt;

&lt;p&gt;安装 Visual C++ Build Tools 2015、MySQL Connector C 6.1、MariaDB connector&lt;/p&gt;

&lt;p&gt;将 MariaDB 安装目录下相应的文件复制到：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;C:\Program Files (x86)\MySQL\MySQL Connector C 6.1\include\mariadb
C:\Program Files (x86)\MySQL\MySQL Connector C 6.1\lib\mariadb
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;参考资料：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;https://devblogs.microsoft.com/python/unable-to-find-vcvarsall-bat/&lt;/li&gt;
  &lt;li&gt;https://stackoverflow.com/questions/51294268/pip-install-mysqlclient-returns-fatal-error-c1083-cannot-open-file-mysql-h&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;docker-compose-中的服务需要等待其他服务启动完成后再执行&quot;&gt;docker-compose 中的服务需要等待其他服务启动完成后再执行&lt;/h2&gt;

&lt;p&gt;使用 docker-compose 的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;healthchecks&lt;/code&gt; 命令&lt;/p&gt;

&lt;p&gt;参考资料：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;https://stackoverflow.com/questions/31746182/docker-compose-wait-for-container-x-before-starting-y/41854997#41854997&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;celery-task-中无法创建子进程&quot;&gt;Celery Task 中无法创建子进程&lt;/h2&gt;

&lt;p&gt;解决方案：&lt;/p&gt;

&lt;p&gt;使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;billiard.context.Process&lt;/code&gt; 代替 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;multiprocessing.Process&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;参考资料：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;https://github.com/celery/celery/issues/4551&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;celery-resultset调用设置了callback的get方法时阻塞&quot;&gt;Celery ResultSet调用设置了callback的get方法时阻塞&lt;/h2&gt;

&lt;p&gt;原因 ：&lt;/p&gt;

&lt;p&gt;ResultSet.on_ready为一个vine.promise对象，未调用前会一直轮询结果状态&lt;/p&gt;

&lt;p&gt;解决方案（选其一）：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;改用由group()返回的GroupResult&lt;/li&gt;
  &lt;li&gt;传入on_interval参数：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lambda: rs._on_ready() if rs.ready() else None&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;在-windows-运行-celery-task-报错valueerror-not-enough-values-to-unpack-expected-3-got-0&quot;&gt;在 Windows 运行 celery task 报错：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ValueError: not enough values to unpack (expected 3, got 0)&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;celery 4.x 后不再支持 windows，问题与底层的 billiard 相关（拖了 2 年，曾有人提过修复的 PR，不过作者似乎并不愿意 “修复”）&lt;/p&gt;

&lt;p&gt;解决方案（选其一）：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;设置环境变量：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;set FORKED_BY_MULTIPROCESSING=1&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;- P eventlet/gevent/solo&lt;/code&gt; 运行 celery&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;参考资料：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;https://www.distributedpython.com/2018/08/21/celery-4-windows/&lt;/li&gt;
  &lt;li&gt;https://stackoverflow.com/questions/37255548/how-to-run-celery-on-windows/47331438&lt;/li&gt;
  &lt;li&gt;https://github.com/celery/celery/issues/4081&lt;/li&gt;
  &lt;li&gt;https://github.com/celery/celery/issues/4178&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;删除-git-仓库中的-submodule&quot;&gt;删除 git 仓库中的 submodule&lt;/h2&gt;

&lt;p&gt;git 本身没有提供相应的命令，可通过以下步骤手动实现：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git submodule deinit &amp;lt;path_to_submodule&amp;gt;
git rm --cached &amp;lt;path_to_submodule&amp;gt;
git commit-m &quot;Removed submodule&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;参考资料：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;https://gist.github.com/myusuf3/7f645819ded92bda6677&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;修改-git-仓库中-submodule-的-remote-url&quot;&gt;修改 git 仓库中 submodule 的 remote url&lt;/h2&gt;

&lt;p&gt;修改 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.gitmodules&lt;/code&gt; 文件中对应模块的 url 属性&lt;/p&gt;

&lt;p&gt;使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git submodule sync&lt;/code&gt; 命令，将新的 url 更新到文件 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.git/config&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;参考资料：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;https://www.jianshu.com/p/ed0cb6c75e25&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;unitestpatch-无法多次-patch-同一对象&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unitest.patch()&lt;/code&gt; 无法多次 patch 同一对象&lt;/h2&gt;

&lt;p&gt;背景：&lt;/p&gt;

&lt;p&gt;在 test1 中对导入 func_module.func() 进行测试，func() 引用了 moduleA，对 moduleA 进行 patch 并返回 Mock1，执行 func()&lt;/p&gt;

&lt;p&gt;在 test2 中同样导入 func_module.func() 进行测试，func() 引用了 moduleA，重新对对 moduleA 进行 patch 并返回 Mock2，执行 func()&lt;/p&gt;

&lt;p&gt;此时 test2 中 func() 内是用的 moduleA 对象是 test1 中的 Mock1，会导致对 Mock2 做的断言失败&lt;/p&gt;

&lt;p&gt;原因：&lt;/p&gt;

&lt;p&gt;运行 test1 时，对 moduleA 进行了 patch，mock_moduleA 由 func_module 导入并被 func() 使用。运行 test2 时，重新对 moduleA 进行 patch，而由于当前上下文中已存在 moduleA 的导入对象了（test1 时导入的 mock_moduleA），因此解释器没有重新导入，直接使用了 test1 时的 mock_moduleA。究其根本原因，应该是 pytest 对每个 test 的隔离不够充分，使得 test1 中的模块导入链影响了 test2&lt;/p&gt;

&lt;p&gt;解决方案：&lt;/p&gt;

&lt;p&gt;应改为对 func_module.moduleA 进行 patch（被 func() 直接使用），而非 patch 全局的 moduleA（被 func_module 导入）&lt;/p&gt;

&lt;p&gt;参考资料：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;https://stackoverflow.com/questions/5341147/how-to-patch-a-modules-internal-functions-with-mock&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;pyppeteer-无法执行-setcookie&quot;&gt;Pyppeteer 无法执行 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setCookie()&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;执行 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setCookie()&lt;/code&gt; 时需为参数指定对应的 url&lt;/p&gt;

&lt;p&gt;参考资料：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;https://github.com/miyakogi/pyppeteer/issues/94&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;pyppeteer-访问部分站点导致与-chromium-的-websockets-连接关闭错误码-1006&quot;&gt;Pyppeteer 访问部分站点导致与 chromium 的 websockets 连接关闭（错误码 1006）&lt;/h2&gt;

&lt;p&gt;原因：&lt;/p&gt;

&lt;p&gt;是 chromium 的 websockets 服务端的问题所导致的，websockets&amp;gt;6 会有一个 ping-pong 的超时判断，若出现超时则会关闭连接&lt;/p&gt;

&lt;p&gt;解决方案（选其一）：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pyppeteer/connection.py&lt;/code&gt; 第 44 行为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;websockets.client.connect()&lt;/code&gt; 增加 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ping_interval=None, ping_timeout=None&lt;/code&gt; 参数（websockets&amp;gt;6）&lt;/li&gt;
  &lt;li&gt;将 websockets 降级至 6.0&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;参考资料：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;https://github.com/miyakogi/pyppeteer/issues/62&lt;/li&gt;
  &lt;li&gt;https://github.com/miyakogi/pyppeteer/pull/160&lt;/li&gt;
  &lt;li&gt;https://bugs.chromium.org/p/chromium/issues/detail?id=865002&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;pyppeteer-在-scrapy-中同步执行无法充分利用其异步特性&quot;&gt;Pyppeteer 在 scrapy 中同步执行，无法充分利用其异步特性&lt;/h2&gt;

&lt;p&gt;pyppeteer 的并发特性是由 asyncio 以及 Python 3.6 提供的 async、await 关键字支持的，而 scrapy 的并发特性基于 twisted 框架，在使用中需手动做一些调整以让其兼容 asyncio&lt;/p&gt;

&lt;p&gt;参考资料：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;https://github.com/lopuhin/scrapy-pyppeteer&lt;/li&gt;
  &lt;li&gt;https://www.lizenghai.com/archives/24943.html&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;使用-winetricks-安装中文应用时安装fakechinese后中文仍显示为方块&quot;&gt;使用 winetricks 安装中文应用时，安装fakechinese后中文仍显示为方块&lt;/h2&gt;

&lt;p&gt;将 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LANG&lt;/code&gt; 设置为 zh-CN 后再运行 winetricks：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;env LANG=zh_CN.UTF-8 winetricks
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;参考资料：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;http://linux-wiki.cn/wiki/zh-hans/Wine%E7%9A%84%E4%B8%AD%E6%96%87%E6%98%BE%E7%A4%BA%E4%B8%8E%E5%AD%97%E4%BD%93%E8%AE%BE%E7%BD%AE&lt;/li&gt;
  &lt;li&gt;https://blog.csdn.net/mhlwsk/article/details/51919916&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;从-priorityqueue-获取元素时有一定概率触发-typeerror&quot;&gt;从 PriorityQueue 获取元素时有一定概率触发 TypeError&lt;/h2&gt;

&lt;p&gt;背景：&lt;/p&gt;

&lt;p&gt;在 celery-dispatcher 项目中使用了 PriorityQueue 来缓存 AsyncResult，并基于时间来分配优先级，该优先级会随着每次轮询不断调整：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# 缓存 AsyncResult
priority = time.time()
result = pickle.loads(result)
priority_queue.put((priority, result))

# 获取 AsyncResult，并调整优先级
priority, result = result_queue.get()
...
priority += poll_timeout
priority_queue.put((priority, result))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;在实际运行过程中，发现有一定概率会触发以下异常，始终无法稳定复现：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;TypeError: '&amp;lt;' not supported between instances of 'AsyncResult' and 'AsyncResult'
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;原因：&lt;/p&gt;

&lt;p&gt;PriorityQueue 是通过 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sorted(list(entries))[0])&lt;/code&gt; 的方式获取元素的，若传入的元素为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(priority_number, data)&lt;/code&gt;，则在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sorted()&lt;/code&gt; 函数排序时会依次比较 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;priority_number&lt;/code&gt;、&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data&lt;/code&gt;。若此时 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;priority_number&lt;/code&gt; 相同而 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data&lt;/code&gt; 不可比较，则会引发 TypeError&lt;/p&gt;

&lt;p&gt;上述 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;priority&lt;/code&gt; 会随着每次轮询不断调整，有一定概率出现相同 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;priority&lt;/code&gt; 的元素，导致 PriorityQueue 开始比较 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;result&lt;/code&gt;，从而引发了上述异常&lt;/p&gt;

&lt;p&gt;解决方案：&lt;/p&gt;

&lt;p&gt;对于 Python&amp;gt;=3.7，可使用&lt;a href=&quot;https://docs.python.org/3.7/library/queue.html#queue.PriorityQueue&quot;&gt;官方解决方案&lt;/a&gt;，将 PriorityQueue 中的元素封装为 PrioritizedItem&lt;/p&gt;

&lt;p&gt;对于 Python&amp;lt;=3.6，可使用自行定义 PrioritizedItem：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;@total_ordering
class PrioritizedItem:
    def __init__(self, priority, item):
        self.priority = priority
        self.item = item

    def __lt__(self, other):
        return self.priority &amp;lt; other.priority

    def __eq__(self, other):
        return self.priority == other.priority
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;参考资料：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;https://stackoverflow.com/questions/54027861/using-queue-priorityqueue-not-caring-about-comparisons&lt;/li&gt;
  &lt;li&gt;https://docs.python.org/3.7/library/queue.html#queue.PriorityQueue&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;在-django-post_save-中下发-celery-任务后-worker-出现-doesnotexist-报错&quot;&gt;在 Django post_save 中下发 Celery 任务后 worker 出现 DoesNotExist 报错&lt;/h2&gt;

&lt;p&gt;背景：&lt;/p&gt;

&lt;p&gt;在 Django 对象的 post_save signal 中下发了一个 Celery 任务并传入相应的对象 ID，从而在异步地对该对象进行处理。然而在 Celery 任务中获取该对象时出现 DoesNotExist 报错&lt;/p&gt;

&lt;p&gt;解决方案：&lt;/p&gt;

&lt;p&gt;通过以下方式下发 Celery 任务，以便在事务提交后再执行：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;from django.db import transaction
transaction.on_commit(lambda: handle_save_task.apply_async(args=[instance.pk]))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;参考资料：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;https://stackoverflow.com/questions/45276828/handle-post-save-signal-in-celery&lt;/li&gt;
&lt;/ol&gt;
</description>
        <pubDate>Tue, 03 Mar 2020 04:00:00 +0000</pubDate>
        <link>https://www.grassfish.net/2020/03/03/strange-problems/</link>
        <guid isPermaLink="true">https://www.grassfish.net/2020/03/03/strange-problems/</guid>
        
        
      </item>
    
      <item>
        <title>SVN 学习笔记</title>
        <description>&lt;p&gt;最近由于项目的原因开始研究 SVN，虽说这是一款年代久远的工具，在经过了解后发现，即使在当今它还是有很多亮点的。&lt;/p&gt;

&lt;h1 id=&quot;0x00-关于-svn&quot;&gt;0x00 关于 SVN&lt;/h1&gt;

&lt;p&gt;SVN 的全称为 Subversion，是一个开放源代码的版本控制系统，SVN 在 2000 年由 CollabNet Inc 开发，现在发展成为 Apache 软件基金会的一个项目，同样是一个丰富的开发者和用户社区的一部分。&lt;/p&gt;

&lt;p&gt;SVN 的架构：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/svn-notes/svn-arch-diagram.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;0x01-基本概念&quot;&gt;0x01 基本概念&lt;/h1&gt;

&lt;h2 id=&quot;版本控制模型&quot;&gt;版本控制模型&lt;/h2&gt;

&lt;p&gt;SVN 以&lt;strong&gt;复制-修改-合并&lt;/strong&gt;模型为主，但是对某些类型的文件仍然需要使用&lt;strong&gt;加锁-修改-解锁&lt;/strong&gt;模型。&lt;strong&gt;复制-修改-合并&lt;/strong&gt;模型要求文件是支持合并的—也就是说文件是基于行的文本文件（例如程序源代码文件），但是对二进制文件（例如图片和音频文件）来说，合并有冲突的修改几乎是不可能完成的。在这种情况下，串行地修改文件就显得非常有必要。如果没有串行访问，用户花费大量时间作出的修改很可能会被丢弃。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;加锁-修改-解锁&lt;/strong&gt;模型：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/svn-notes/ch02dia3.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;复制-修改-合并&lt;/strong&gt;模型：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/svn-notes/ch02dia4.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/svn-notes/ch02dia5.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;仓库&quot;&gt;仓库&lt;/h2&gt;

&lt;p&gt;仓库是存放 SVN 的版本控制数据的中央位置，用户及其软件通过工作副本与仓库交互。SVN 实现仓库的方式与其他版本控制系统非常类似。与工作副本不同，一个 SVN 仓库是一个抽象的实体，可以被 SVN 的库和工具进行独占性地操作。&lt;/p&gt;

&lt;h2 id=&quot;工作副本&quot;&gt;工作副本&lt;/h2&gt;

&lt;p&gt;工作副本（working copy）是仓库的特定版本数据在本地的副本，用户可以自由地对它进行操作。工作副本中除了存放被版本控制的文件外，还有用于跟踪文件和与服务器通信的元数据。对其他软件来说，工作副本只是一个普通的本地目录，所以即使它们不具备版本控制功能也可以对工作副本进行读写。SVN 的客户端工具负责管理工作副本，以及与仓库通信。&lt;/p&gt;

&lt;h2 id=&quot;版本号&quot;&gt;版本号&lt;/h2&gt;

&lt;p&gt;SVN 客户端将任意多的文件和目录的修改作为一个原子事务提交给仓库。原子事务的意思是要么所有的修改都被仓库接受，要么一个也没有。SVN 尽量保证即使是在程序崩溃，操作系统崩溃，网络断开和有其他 用户干扰的情况下，也能维持住原子性。&lt;/p&gt;

&lt;p&gt;仓库每接受一次提交都会为文件系统树创建一个新状态，叫作一个版本号（revision）。每一个版本号都与一个独一无二的自然数相关联，后一个版本号都比前一个大一。新创建的仓库的初始版本号是 0，除了一个空的根目录外，什么也没有。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/svn-notes/ch02dia7.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;0x02-svn-的工作副本&quot;&gt;0x02 SVN 的工作副本&lt;/h1&gt;

&lt;p&gt;一个 SVN 工作副本是用户本地系统中的一个普通目录，用户可以按照自己的要求对存放在目录中的文件进行编辑，如果是源代码文件，用户也可以按照通常的方式对它们进行编译。工作副本是用户的私有工作空间：除非用户明确地要求 SVN，否则它不会让工作副本合并其他人的修改，也不会把用户的修改暴露给其他人。用户可以为同一个项目创建多个工作副本。&lt;/p&gt;

&lt;p&gt;如果用户修改了工作副本中的文件，并且确认了修改是正确的，此时可以使用 SVN 提供的命令来”发布”修改（通过把修改保存到仓库中），于是项目中的其他人就可以看到你的修改。如果其他人也发布了他们的修改，SVN 也提供了命令把他们的修改合并到你的工作副本中（通过读取仓库）。&lt;/p&gt;

&lt;p&gt;工作副本还会包含一些额外的文件，这些文件由 SVN 创建并维护，用于命令的正常运行。每一个工作副本中都有一个名为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.svn&lt;/code&gt; 的子目录，它是工作副本的管理目录。管理目录中的文件可以帮助 SVN 识别哪些文件含有未发布的修改，哪些文件是过时的。&lt;/p&gt;

&lt;h2 id=&quot;工作副本的工作原理&quot;&gt;工作副本的工作原理&lt;/h2&gt;

&lt;p&gt;SVN 为工作副本中的每一个文件记录两项信息:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;版本号：这被称为文件的工作版本号（working revision）&lt;/li&gt;
  &lt;li&gt;时间戳：记录了本地文件最近一次被仓库更新是在什么时候&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;有了这些信息后，通过与仓库通信，SVN 就可以判断出 每一个工作文件处于以下 4 种状态中的哪一种:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;当前未修改的：文件在工作副本中未被修改，并且在工作版本号之后还没有人提交过该文件的修改。对文件执行 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;svn commit&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;svn update&lt;/code&gt; 都不会产生任何效果.&lt;/li&gt;
  &lt;li&gt;当前已修改的：文件在工作副本中已被修改，并且在一次更新以来还没有人向仓库提交过该文件的修改。本地有未提交的修改，于是执行 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;svn commit&lt;/code&gt; 将会成功地把修改提交到仓库中，而 svn update 不会产生任何效果.&lt;/li&gt;
  &lt;li&gt;过时未修改的：文件在工作副本中未被修改，但是在上一次更新之后有人往仓库提交了该文件的修改。为了让文件和最新版本保持同步，应该执行更新操作。对文件执行 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;svn commit&lt;/code&gt; 不会产生任何效果，执行 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;svn update&lt;/code&gt; 将 把仓库中的最新修改合并到文件中.&lt;/li&gt;
  &lt;li&gt;过时且已修改的：文件在本地工作副本和仓库都被修改了。对文件执行 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;svn commit&lt;/code&gt; 会由于文件已过时而失败。首先应该更新文件，命令 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;svn update&lt;/code&gt; 试图 把仓库的修改合并到本地。如果 SVN 不能自动地以一种 合理的方式完成合并，就会把冲突交由用户来解决.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1 id=&quot;0x03-svn-基本用法&quot;&gt;0x03 SVN 基本用法&lt;/h1&gt;

&lt;h2 id=&quot;往仓库中添加数据&quot;&gt;往仓库中添加数据&lt;/h2&gt;

&lt;p&gt;命令 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;svn import&lt;/code&gt; 可以快速地向仓库中添加新文件或目录。&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;svn import&lt;/code&gt; 不要求工作副本，新增的文件会马上提交到仓库中。使用该命令的典型情况是用户想要把一个已存在的目录添加到 SVN 仓库中，例如：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;svn import SRC DST [-m MSG]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;上面的例子把本地目录 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mytree&lt;/code&gt; 中的内容添加到仓库的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;some/project&lt;/code&gt; 目录中。注意，用户在导入前无需创建新目录——&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;svn import&lt;/code&gt; 会自动完成这些工作。提交后，用户就可以在仓库中看到新增的文件和目录：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;svn list SRC
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;创建工作副本&quot;&gt;创建工作副本&lt;/h2&gt;

&lt;p&gt;检出（checkout）仓库中的目录将会在用户的本地主机上创建一个该目录的工作副本。除非特意指定，否则这个副本将包含仓库最新版本的数据：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;svn checkout SRC
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;更新工作副本&quot;&gt;更新工作副本&lt;/h2&gt;

&lt;p&gt;如果某个项目正在被多个工作副本修改，用户就需要更新自己本地的工作副本，以获取其他人提交的修改:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;svn update
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;修改工作副本&quot;&gt;修改工作副本&lt;/h2&gt;

&lt;p&gt;工作副本支持的修改类型分为两种：文件修改（file changes）和目录修改（tree changes）。&lt;strong&gt;文件修改&lt;/strong&gt;不需要告知 SVN，用户可以使用任意一种自己喜欢的工具来修改文件，SVN 可以自动检测到哪些文件发生了变化。&lt;strong&gt;目录修改&lt;/strong&gt;涉及到目录结构的变化，例如添加和删除文件、重命名文件和目录、复制文件和目录。目录修改要使用 SVN 的命令完成。文件修改和目录修改只有在提交后才会更新到仓库中：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;svn add FOO
svn delete FOO
svn copy FOO BAR
svn move FOO BAR
svn mkdir FOO
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;审核修改&quot;&gt;审核修改&lt;/h2&gt;

&lt;p&gt;在提交之前，应该查看一下自己到底修改了哪些东西。&lt;/p&gt;

&lt;p&gt;查看修改的整体概述：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;svn status [FOO]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;查看修改的细节：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;svn diff [FOO]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;修正错误&quot;&gt;修正错误&lt;/h2&gt;

&lt;p&gt;SVN 提供了一种简便的方法来撤消工作副本中的修改，把文件或目录恢复到修改前的样子：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;svn revert [-r REV] [FOO]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;解决冲突&quot;&gt;解决冲突&lt;/h2&gt;

&lt;p&gt;当一个用户正在修改文件时，其他人可能已经把自己的修改提交到了服务器上。为了防止在提交修改时，由于工作副本过旧导致提交失败，用户需要把其他人的修改更新到本地：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;svn update
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;如果命令的执行结果有冲突产生：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;svn resolve --accept [ACT] [FOO]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;关于 ACT：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;base：使用上一次检出时版本&lt;/li&gt;
  &lt;li&gt;mine-full：保留自己的修改&lt;/li&gt;
  &lt;li&gt;theirs-full：保留从服务器收到的更新&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;提交修改&quot;&gt;提交修改&lt;/h2&gt;

&lt;p&gt;把工作副本的修改提交到仓库中，如果修改 被接受，其他用户就可以看到这些修改：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;svn commit [-m MSG]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;检查历史&quot;&gt;检查历史&lt;/h2&gt;

&lt;p&gt;从行的级别上查看修改的内容：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;svn diff [-r REV]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;查看和版本号绑定的日志消息，及其日期、作者、以及受影响的文件路径：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;svn log  [-r REV]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;根据给定的版本号，输出文件在该版本下的内容：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;svn cat [-r REV]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;根据给定的版本号，查看该版本下的文件的每一行的最后一次修改信息：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;svn annotate [-r REV]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;根据给定的版本号，列出仓库在该版本下的文件与目录清单：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;svn list [-r REV] [SRC]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;0x04-svn-与-git-的区别&quot;&gt;0x04 SVN 与 Git 的区别&lt;/h1&gt;

&lt;ol&gt;
  &lt;li&gt;SVN 仓库为集中式管理，而 Git 仓库为分布式管理&lt;/li&gt;
  &lt;li&gt;SVN 的权限管理可精确到具体路径，而 Git 只能做到仓库级别&lt;/li&gt;
  &lt;li&gt;SVN 可下载仓库下的某一子目录，而 Git 只能下载完整的仓库&lt;/li&gt;
  &lt;li&gt;SVN 一个仓库可对应多个项目，而 Git 一个仓库对应一个项目&lt;/li&gt;
  &lt;li&gt;SVN 的分支与标签基于文件目录，而 Git 则基于引用&lt;/li&gt;
  &lt;li&gt;SVN 对文件的完整性依赖于服务端给出的校验码，而 Git 则基于自身的机制（通过 SHA-1 计算的 Commit ID）&lt;/li&gt;
&lt;/ol&gt;

&lt;h1 id=&quot;参考资料&quot;&gt;参考资料&lt;/h1&gt;

&lt;ol&gt;
  &lt;li&gt;http://svnbook.red-bean.com/nightly/zh/svn-book.html#svn.advanced.props.special.ignore&lt;/li&gt;
&lt;/ol&gt;
</description>
        <pubDate>Sat, 17 Aug 2019 08:00:00 +0000</pubDate>
        <link>https://www.grassfish.net/2019/08/17/svn-notes/</link>
        <guid isPermaLink="true">https://www.grassfish.net/2019/08/17/svn-notes/</guid>
        
        <category>Linux</category>
        
        
      </item>
    
      <item>
        <title>防范恶意域名解析</title>
        <description>&lt;p&gt;主要目的是通过配置 Web 服务器的方式，防范通过其他域名指向我们的服务器并访问的情况。&lt;/p&gt;

&lt;h1 id=&quot;0x00-漏洞危害&quot;&gt;0x00 漏洞危害&lt;/h1&gt;

&lt;ol&gt;
  &lt;li&gt;若该域名原本指向非法网站，重新指向我们的服务器并被工信部扫描到的话，会影响该服务器的域名备案&lt;/li&gt;
  &lt;li&gt;会引发搜索引擎惩罚，连带 IP 受到牵连&lt;/li&gt;
  &lt;li&gt;会导致流量被劫持到别的域名，从而遭到广告联盟的封杀&lt;/li&gt;
&lt;/ol&gt;

&lt;h1 id=&quot;0x01-nginx-配置&quot;&gt;0x01 Nginx 配置&lt;/h1&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;if ($host !~ ^(www.example.com)$ ) {
    return 403;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;0x02-apache-配置&quot;&gt;0x02 Apache 配置&lt;/h1&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;VirtualHost *:80&amp;gt;
    ServerName default
    &amp;lt;Location /&amp;gt;
        Order Allow,Deny
        Deny from all
    &amp;lt;/Location&amp;gt;
&amp;lt;/VirtualHost&amp;gt;

&amp;lt;VirtualHost *:80&amp;gt;
    ServerName www.example.com
    DocumentRoot &quot;/home/www&quot;
&amp;lt;/VirtualHost&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;0x03-关于-apache-配置的说明&quot;&gt;0x03 关于 Apache 配置的说明&lt;/h1&gt;

&lt;p&gt;之所以要为 Apache 的配置附加单独的说明，是因为感觉其配置命令没有 Nginx 那么直观，且存在一些隐式的内部机制，若没有阅读过官方文档的话容易踩坑。&lt;/p&gt;

&lt;p&gt;关于 Apache 的配置可以引申出三个问题：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;为什么要使用两个 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VirtualHost&lt;/code&gt;？&lt;/li&gt;
  &lt;li&gt;为什么要将用于拦截的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VirtualHost&lt;/code&gt; 放在第一个位置？&lt;/li&gt;
  &lt;li&gt;为什么第一个 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VirtualHost&lt;/code&gt; 的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ServerName&lt;/code&gt; 为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;default&lt;/code&gt;？&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;1-为什么要使用两个-virtualhost&quot;&gt;1 为什么要使用两个 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VirtualHost&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;需要使用一个 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VirtualHost&lt;/code&gt; 处理正常域名的访问请求，另一个 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VirtualHost&lt;/code&gt; 拦截其他域名（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Host&lt;/code&gt; 字段非 Apache 指定的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ServerName&lt;/code&gt;）的访问请求。&lt;/p&gt;

&lt;h2 id=&quot;2-为什么要将用于拦截的-virtualhost-放在第一个位置&quot;&gt;2 为什么要将用于拦截的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VirtualHost&lt;/code&gt; 放在第一个位置&lt;/h2&gt;

&lt;p&gt;Apache 配置示例的官方文档 &lt;a href=&quot;https://httpd.apache.org/docs/current/vhosts/examples.html#purename&quot;&gt;在此&lt;/a&gt;，其中关于 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VirtualHost&lt;/code&gt; 处理顺序的描述如下：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Due to the fact that the virtual host with ServerName www.example.com is first in the configuration file, it has the highest priority and can be seen as the default or primary server. That means that if a request is received that does not match one of the specified ServerName directives, it will be served by this first &lt;VirtualHost&gt;.&lt;/VirtualHost&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;也就是说，Apache 对于 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VirtualHost&lt;/code&gt; 的处理存在一个 fallback 机制：Apache 按先后顺序处理 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VirtualHost&lt;/code&gt;，若所有的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ServerName&lt;/code&gt; 都没被匹配，则使用第一个 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VirtualHost&lt;/code&gt; 中的处理逻辑响应请求（会忽略其中的匹配条件）。因此将 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Deny&lt;/code&gt; 的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VirtualHost&lt;/code&gt; 放在第一个位置可以实现 Apache 中的域名白名单机制。&lt;/p&gt;

&lt;h2 id=&quot;3-为什么第一个-virtualhost-的-servername-为-default&quot;&gt;3 为什么第一个 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VirtualHost&lt;/code&gt; 的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ServerName&lt;/code&gt; 为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;default&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;由上一小节可知，当所有的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ServerName&lt;/code&gt; 都没被匹配时，会使用第一个 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VirtualHost&lt;/code&gt; 中的处理逻辑响应请求，并忽略其中的匹配条件。因此当发生 fallback 时，无论第一个 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VirtualHost&lt;/code&gt; 中的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ServerName&lt;/code&gt; 为何值都会被忽略，Apache 只关注其中的处理逻辑。&lt;/p&gt;

&lt;p&gt;另外，第一个 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VirtualHost&lt;/code&gt; 的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ServerName&lt;/code&gt; 也是必须要指定的，否则 Apache 会直接匹配到第一个 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VirtualHost&lt;/code&gt; 并拦截所有域名的访问请求。&lt;/p&gt;

&lt;h1 id=&quot;参考资料&quot;&gt;参考资料&lt;/h1&gt;

&lt;ol&gt;
  &lt;li&gt;https://www.cnblogs.com/dadonggg/p/8398112.html&lt;/li&gt;
  &lt;li&gt;https://httpd.apache.org/docs/current/vhosts/examples.html&lt;/li&gt;
&lt;/ol&gt;
</description>
        <pubDate>Fri, 16 Aug 2019 10:00:00 +0000</pubDate>
        <link>https://www.grassfish.net/2019/08/16/deny-other-domain/</link>
        <guid isPermaLink="true">https://www.grassfish.net/2019/08/16/deny-other-domain/</guid>
        
        <category>运维安全</category>
        
        
      </item>
    
      <item>
        <title>SQL 注入之宽字符注入</title>
        <description>&lt;h1 id=&quot;0x00-mysql-字符集&quot;&gt;0x00 MySQL 字符集&lt;/h1&gt;

&lt;p&gt;通过运行如下语句，可以看到 MySQL 有 8 个与字符集相关的环境变量：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;MariaDB [(none)]&amp;gt; SHOW VARIABLES LIKE 'character%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | gbk                        |
| character_set_connection | gbk                        |
| character_set_database   | gbk                        |
| character_set_filesystem | binary                     |
| character_set_results    | gbk                        |
| character_set_server     | gbk                        |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.002 sec)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;其中各个变量的作用如下：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;character_set_client&lt;/code&gt;：MySQL 服务端认为客户端连接所使用的编码&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;character_set_connection&lt;/code&gt;：没有指定编码时 MySQL 服务端处理所使用的编码&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;character_set_database&lt;/code&gt;：创建数据库时，如果没有指定编码，默认的编码值&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;character_set_results&lt;/code&gt;：查询结果以这个编码发送给客户端&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;character_set_server&lt;/code&gt;：服务器的默认编码，以上所有的变量，默认都和这个设置保持一致&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;其中 3 个主要变量（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;character_set_client&lt;/code&gt;、&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;character_set_connection&lt;/code&gt;、&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;character_set_results&lt;/code&gt;）的修改方式如下：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;非持久化：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SET NAMES 'charset_name' [COLLATE 'collation_name']&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;持久化：修改 MySQL 服务端配置文件的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;character-set-server&lt;/code&gt;、&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;skip-character-set-client-handshake&lt;/code&gt; 字段&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;在处理客户端查询时，MySQL 中字符集的转换过程如下：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;MySQL 服务端收到请求时，将请求数据从 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;character_set_client&lt;/code&gt; 转换为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;character_set_connection&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;进行内部操作前，将请求数据从 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;character_set_connection&lt;/code&gt; 转换为内部操作字符集，其确定方法如下：
    &lt;ul&gt;
      &lt;li&gt;使用每个数据字段的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CHARACTER SET&lt;/code&gt; 设定值&lt;/li&gt;
      &lt;li&gt;若上述值不存在，则使用对应数据表的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DEFAULT CHARACTER SET&lt;/code&gt; 设定值(MySQL 扩展，非 SQL 标准)&lt;/li&gt;
      &lt;li&gt;若上述值不存在，则使用对应数据库的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DEFAULT CHARACTER SET&lt;/code&gt; 设定值&lt;/li&gt;
      &lt;li&gt;若上述值不存在，则使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;character_set_server&lt;/code&gt; 设定值&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;将操作结果从内部操作字符集转换为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;character_set_results&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h1 id=&quot;0x01-产生原因&quot;&gt;0x01 产生原因&lt;/h1&gt;

&lt;p&gt;首先，MySQL 服务端会根据当前会话的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;character_set_client&lt;/code&gt; 变量解码客户端传来的 SQL 语句。当该变量的值为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gbk&lt;/code&gt; 时，MySQL 会将符合 GBK 定义的双字节解码为汉字：首字节在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;81-FE&lt;/code&gt; 范围内，尾字节在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;40-FE&lt;/code&gt; 范围内。&lt;/p&gt;

&lt;p&gt;然后，假设攻击者使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\xdf'&lt;/code&gt; 来逃逸单引号，后端对用户输入进行了转义，单引号 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;'&lt;/code&gt; 被 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\&lt;/code&gt;（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\x5c&lt;/code&gt;）转义，形成了 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\xdf\x5c'&lt;/code&gt;。而 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\xdf&lt;/code&gt; 在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;81-FE&lt;/code&gt; 的范围之间，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\x5c&lt;/code&gt; 在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;40-FE&lt;/code&gt; 的范围之间，因此 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\xdf\x5c&lt;/code&gt; 一起被解码为一个汉字，使得 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;'&lt;/code&gt; 摆脱了 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\&lt;/code&gt; 的转义。&lt;/p&gt;

&lt;p&gt;漏洞产生的场景如下：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;MySQL &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;character_set_client&lt;/code&gt; 被配置为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gbk&lt;/code&gt;，业务使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;addslashes()&lt;/code&gt; / &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mysql_escape_string()&lt;/code&gt; / &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;magic_quotes_gpc&lt;/code&gt; 转义用户输入&lt;/li&gt;
  &lt;li&gt;业务通过 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SET NAMES 'gbk'&lt;/code&gt; 将连接字符集设置为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gbk&lt;/code&gt;，并使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;addslashes()&lt;/code&gt; / &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mysql_escape_string()&lt;/code&gt; / &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;magic_quotes_gpc&lt;/code&gt; 转义用户输入&lt;/li&gt;
  &lt;li&gt;业务直接使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mysql_real_escape_string()&lt;/code&gt; 转义用户输入，但未通过 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mysql_set_charset()&lt;/code&gt; 设置连接句柄的字符集（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SET NAMES&lt;/code&gt; 无用）&lt;/li&gt;
&lt;/ol&gt;

&lt;h1 id=&quot;0x02-修复方案&quot;&gt;0x02 修复方案&lt;/h1&gt;

&lt;ol&gt;
  &lt;li&gt;使用参数化查询&lt;/li&gt;
  &lt;li&gt;先使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mysql_set_charset()&lt;/code&gt; 设置连接字符集为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gbk&lt;/code&gt;，再使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mysql_real_escape_string()&lt;/code&gt; 来转义用户输入&lt;/li&gt;
  &lt;li&gt;手动将 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;character_set_client&lt;/code&gt; 设置为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;binary&lt;/code&gt;：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SET character_set_connection=gbk, character_set_results=gbk,character_set_client=binary&lt;/code&gt;，再使用相应函数转义用户输入&lt;/li&gt;
&lt;/ol&gt;

&lt;h1 id=&quot;参考资料&quot;&gt;参考资料&lt;/h1&gt;

&lt;ol&gt;
  &lt;li&gt;https://www.leavesongs.com/PENETRATION/mutibyte-sql-inject.html&lt;/li&gt;
  &lt;li&gt;http://www.laruence.com/2010/04/12/1396.html&lt;/li&gt;
  &lt;li&gt;http://www.laruence.com/2008/01/05/12.html&lt;/li&gt;
&lt;/ol&gt;
</description>
        <pubDate>Wed, 20 Mar 2019 15:00:00 +0000</pubDate>
        <link>https://www.grassfish.net/2019/03/20/sqli-wide-character/</link>
        <guid isPermaLink="true">https://www.grassfish.net/2019/03/20/sqli-wide-character/</guid>
        
        <category>Web安全</category>
        
        <category>SQL注入</category>
        
        <category>渗透</category>
        
        
      </item>
    
      <item>
        <title>iptables 学习笔记</title>
        <description>&lt;p&gt;以往面对 iptables 的场景比较少，对其的了解仅存在于命令使用的层面。现在重新开始学习 iptables，终于弄懂了以前很模糊的一些概念，总结了以下的笔记。&lt;/p&gt;

&lt;h1 id=&quot;0x00-关于-iptables&quot;&gt;0x00 关于 iptables&lt;/h1&gt;

&lt;p&gt;iptables 是一个配置 Linux 内核防火墙的命令行工具，可以检测、修改、转发、重定向和丢弃网络数据包。iptables 只是用户空间的一个客户端代理，负责实际数据包处理的则是内核空间的 Netfilter 模块。&lt;/p&gt;

&lt;h1 id=&quot;0x01-表链关系&quot;&gt;0x01 表链关系&lt;/h1&gt;

&lt;p&gt;表由一系列的链组成，链由一组按顺序排列的规则组成。每一条规则包含一个匹配条件和相应的动作，若数据包符合匹配条件，则该动作会被执行。一个数据包从链路到达本地网络接口（若 MAC 地址符合则会由内核中相应的驱动程序接收），再经路由判断（IP 是否符合）送达相应的应用程序，最后通过网络接口返回到链路的过程中，数据包的流向如下：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/iptables-notes/tables_traverse.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;如上图所示，一个表中可以包含几个链，同时一个链中也可以出现几个表。可以分别从表和链的角度，来看待二者的对应关系。&lt;/p&gt;

&lt;h2 id=&quot;以表分类&quot;&gt;以表分类&lt;/h2&gt;

&lt;p&gt;从功能的角度来说，iptables 的规则可以按表进行分类。每个表保存负责同一功能的一系列规则。所有的表如下：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;raw&lt;/code&gt;：用于配置数据包（关闭连接追踪）&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mangle&lt;/code&gt;：用于修改数据包（TOS、TTL、MARK）&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nat&lt;/code&gt;：用于网络地址转换（SNAT、DNAT、端口转发）&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;filter&lt;/code&gt;：用于过滤数据包（实现软件防火墙）&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;security&lt;/code&gt;：用于强制访问控制（依赖 SELinux）&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;以链分类&quot;&gt;以链分类&lt;/h2&gt;

&lt;p&gt;从时间顺序的角度来说，iptables 的规则可以按链进行分类。当数据包抵达一个链时，Netfilter 按照 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;raw -&amp;gt; mangle -&amp;gt; nat -&amp;gt; filter -&amp;gt; security&lt;/code&gt; 的顺序来匹配表（无该表则忽略），并遍历匹配表中的每一条规则。所有的链如下：&lt;/p&gt;

&lt;p&gt;根据数据包的目的地址，若是发往本地的包：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PREROUTING&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INPUT&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;本地应用程序&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OUTPUT&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;POSTROUTING&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;若不是发往本地的包：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PREROUTING&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FORWARD&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;POSTROUTING&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;常用表的功能&quot;&gt;常用表的功能&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mangle&lt;/code&gt; 表：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;TOS：设置或改变数据包的服务类型域（网络上的数据包如何被路由等策略）&lt;/li&gt;
  &lt;li&gt;TTL：改变数据包的生存时间域&lt;/li&gt;
  &lt;li&gt;MARK：给包设置特殊的标记&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nat&lt;/code&gt; 表：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;DNAT：改变包的目的地址，使包能重路由到某台主机&lt;/li&gt;
  &lt;li&gt;SNAT：改变包的源地址，使多个主机公用一个公网 IP&lt;/li&gt;
  &lt;li&gt;MASQUERADE：// TODO&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;filter&lt;/code&gt; 表：&lt;/p&gt;

&lt;p&gt;用来过滤数据包，可根据包的内容对包做 DROP 或 ACCEPT。&lt;/p&gt;

&lt;h1 id=&quot;0x02-状态机制&quot;&gt;0x02 状态机制&lt;/h1&gt;

&lt;p&gt;本地产生的包的跟踪由 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OUTPUT&lt;/code&gt; 链处理，其他所有连接跟踪都由 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PREROUTING&lt;/code&gt; 链处理（iptables 会在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PREROUTING&lt;/code&gt; 链里重新计算所有状态）：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;若会话的第一个数据包由本地应用程序发出，状态就会在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OUTPUT&lt;/code&gt; 链里被设置为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NEW&lt;/code&gt;；当我们收到回应的包时，状态就会在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PREROUTING&lt;/code&gt; 链里被设置为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ESTABLISHED&lt;/code&gt;。&lt;/li&gt;
  &lt;li&gt;若会话的第一个数据包不是由本地应用程序发出，状态就会在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PREROUTING&lt;/code&gt; 链里被设置为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NEW&lt;/code&gt;。&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;数据包在用户空间的状态&quot;&gt;数据包在用户空间的状态&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NEW&lt;/code&gt;：还未建立好的连接（刚发出第一个包）&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ESTABLISHED&lt;/code&gt;：已建立的连接（已在内核里注册过 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NEW&lt;/code&gt; 状态）&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RELATED&lt;/code&gt;：已经存在的、处于已建立状态的连接生成的新连接&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INVALID&lt;/code&gt;：说明数据包不能被识别属于哪个连接或没有任何状态&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;TCP 连接在建立过程中的状态变化：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/iptables-notes/state-tcp-connecting.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;TCP 连接在关闭过程中的状态变化：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/iptables-notes/state-tcp-closing.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;数据包在内核空间的状态&quot;&gt;数据包在内核空间的状态&lt;/h2&gt;

&lt;p&gt;可通过 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/proc/net/nf_conntrack&lt;/code&gt; 查看内核保存在内存中的状态信息。&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NONE&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ESTABLISHED&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SYN_SENT&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SYN_RECV&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FIN_WAIT&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TIME_WAIT&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CLOSE&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CLOSE_WAIT&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LAST_ACK&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LISTEN&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h1 id=&quot;0x03-规则&quot;&gt;0x03 规则&lt;/h1&gt;

&lt;p&gt;规则是决定如何处理一个数据包的语句。如果一个包符合规则中的 &lt;strong&gt;匹配条件&lt;/strong&gt;，我们就运行 &lt;strong&gt;target/jump&lt;/strong&gt; 指令。&lt;/p&gt;

&lt;h2 id=&quot;匹配条件&quot;&gt;匹配条件&lt;/h2&gt;

&lt;p&gt;匹配条件可分为以下 3 种，不同类型的匹配条件包含了不同的参数：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;通用匹配：可直接使用而不需要前提条件&lt;/li&gt;
  &lt;li&gt;隐含匹配：跟随匹配协议自动装载入内核（自动匹配该协议的包的一些特点）&lt;/li&gt;
  &lt;li&gt;显式匹配：必须用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-m/--match&lt;/code&gt; 装载（扩展匹配）&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;targetsjumps&quot;&gt;Targets/Jumps&lt;/h2&gt;

&lt;p&gt;target/jump 决定符合条件的包到何处去。&lt;/p&gt;

&lt;h3 id=&quot;jump-的目标是一个在同一个表内的链&quot;&gt;jump 的目标是一个在同一个表内的链&lt;/h3&gt;

&lt;p&gt;我们在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;filter&lt;/code&gt; 表中建一个名为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tcp_packets&lt;/code&gt; 的链，然后再把它作为 jump 的目标：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;iptables -N tcp_packets
iptables -A INPUT -p tcp -j tcp_packets
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;这样当数据包到达 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INPUT&lt;/code&gt; 链后会跳入 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tcp_packets&lt;/code&gt; 链，开始在子链中遍历。如果未被子链中的任何规则匹配（到达了链的结尾），则会退到 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INPUT&lt;/code&gt; 链的下一条规则继续向后匹配；如果在子链中被 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ACCEPT&lt;/code&gt; 了，也就相当于在父链中被 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ACCEPT&lt;/code&gt; 了，那么它不会再经过父链中的其他规则。&lt;/p&gt;

&lt;h3 id=&quot;target-的目标是具体的操作&quot;&gt;target 的目标是具体的操作&lt;/h3&gt;

&lt;p&gt;target 可分为两类，一类操作完后会停止匹配（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ACCEPT&lt;/code&gt;、&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DROP&lt;/code&gt;、&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;REJECT&lt;/code&gt;），另一类对包操作完后可继续对链中的其他规则进行匹配（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LOG&lt;/code&gt;、&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ULOG&lt;/code&gt;、&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TOS&lt;/code&gt;）。&lt;/p&gt;

&lt;p&gt;target 有以下几种：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ACCEPT&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DNAT&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DROP&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LOG&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MARK&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MASQUERADE&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MIRROR&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;QUEUE&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;REDIRECT&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;REJECT&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RETURN&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SNAT&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TOS&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TTL&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ULOG&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h1 id=&quot;参考资料&quot;&gt;参考资料&lt;/h1&gt;

&lt;ol&gt;
  &lt;li&gt;https://www.frozentux.net/iptables-tutorial/cn/iptables-tutorial-cn-1.1.19.html&lt;/li&gt;
  &lt;li&gt;http://www.zsythink.net/archives/1199&lt;/li&gt;
  &lt;li&gt;https://wiki.archlinux.org/index.php/Iptables_(简体中文)&lt;/li&gt;
&lt;/ol&gt;
</description>
        <pubDate>Wed, 09 Jan 2019 14:00:00 +0000</pubDate>
        <link>https://www.grassfish.net/2019/01/09/iptables-notes/</link>
        <guid isPermaLink="true">https://www.grassfish.net/2019/01/09/iptables-notes/</guid>
        
        <category>Linux</category>
        
        
      </item>
    
      <item>
        <title>LVM 容量调整日志</title>
        <description>&lt;h1 id=&quot;0x00-前言&quot;&gt;0x00 前言&lt;/h1&gt;

&lt;p&gt;博主目前的磁盘分区采用的是 LVM-on-LUKS 方案，布局如下：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;+-----------------------------------------------------------------------+ +----------------+
| Logical volume 1      | Logical volume 2      | Logical volume 3      | | Boot partition |
|                       |                       |                       | |                |
| [SWAP]                | /                     | /home                 | | /boot          |
|                       |                       |                       | |                |
| /dev/MyVol/swap       | /dev/MyVol/root       | /dev/MyVol/home       | |                |
|_ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _| |                |
|                                                                       | |                |
|                         LUKS encrypted partition                      | |                |
|                           /dev/sdb2                                   | | /dev/sdb1      |
+-----------------------------------------------------------------------+ +----------------+
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;其中：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/mapper/cryptolvm&lt;/code&gt; 为使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LUKS&lt;/code&gt; 在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/sdb2&lt;/code&gt; 创建，并写入了 LVM 的特殊头部的物理卷（PV）&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/MyVol&lt;/code&gt; 为卷组（VG）&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/MyVol/{swap,root,home}&lt;/code&gt; 为逻辑卷（LV）&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;由于 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt; 分区目前只分配了 40G（已调整多次），使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pacman&lt;/code&gt; 更新系统时提示剩余空间不够（即使清理了所有软件包缓存…）：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;错误：分区 / 过满：需要 795917 个块，剩余 345532 个块
错误：无法提交处理 (剩余空间不够)
发生错误，没有软件包被更新。
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;0x01-方案一分别调整-fs-与-lv&quot;&gt;0x01 方案一：分别调整 FS 与 LV&lt;/h1&gt;

&lt;p&gt;网上大部分关于 LVM 逻辑卷（LV） resizing 的文章都是按照下面这个步骤来的，由于缩减文件系统容量时需要指定具体大小，实施起来不是很灵活：&lt;/p&gt;

&lt;p&gt;打开加密卷：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cryptsetup luksOpen /dev/sdb2 cryptolvm
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;缩容：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resize2fs&lt;/code&gt; 缩减逻辑卷 A 中文件系统的容量&lt;/li&gt;
  &lt;li&gt;可选：使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;e2fsck&lt;/code&gt; 检查文件系统（排错）&lt;/li&gt;
  &lt;li&gt;使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lvreduce&lt;/code&gt; / &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lvresize&lt;/code&gt; 缩减逻辑卷 A 的容量&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;resize2fs /dev/MyVol/home &amp;lt;NewSize&amp;gt;
e2fsck -f /dev/MyVol/home
lvreduce -L -10G /dev/MyVol/home
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;扩容：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lvextend&lt;/code&gt; / &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lvresize&lt;/code&gt; 扩大逻辑卷 B 的容量&lt;/li&gt;
  &lt;li&gt;使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resize2fs&lt;/code&gt; 扩大逻辑卷 B 中文件系统的容量&lt;/li&gt;
  &lt;li&gt;可选：使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;e2fsck&lt;/code&gt; 检查文件系统（排错）&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;lvextend -l +100%FREE /dev/MyVol/root
resize2fs /dev/MyVol/root
e2fsck -f /dev/MyVol/root
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;0x02-方案二一次性调整-lv&quot;&gt;0x02 方案二：一次性调整 LV&lt;/h1&gt;

&lt;p&gt;根据 ArchWiki，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lvresize&lt;/code&gt; 的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-r&lt;/code&gt; / &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--resizefs&lt;/code&gt; 选项将文件系统调整、LV 调整二者结合了起来，因此使用该种方式调整容量将更加方便。&lt;/p&gt;

&lt;p&gt;打开加密卷：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cryptsetup luksOpen /dev/sdb2 cryptolvm
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;缩容：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;lvresize -L -10G -r /dev/MyVol/home
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;扩容：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;lvresize -l +100%FREE -r /dev/MyVol/root
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;参考资料&quot;&gt;参考资料&lt;/h1&gt;

&lt;ol&gt;
  &lt;li&gt;https://wiki.archlinux.org/index.php/Dm-crypt/Encrypting_an_entire_system#LVM_on_LUKS&lt;/li&gt;
  &lt;li&gt;https://wiki.archlinux.org/index.php/LVM#Resizing_volumes&lt;/li&gt;
  &lt;li&gt;https://wiki.archlinux.org/index.php/Resizing_LVM-on-LUKS&lt;/li&gt;
&lt;/ol&gt;
</description>
        <pubDate>Sun, 04 Nov 2018 16:00:00 +0000</pubDate>
        <link>https://www.grassfish.net/2018/11/04/lvm-resize-log/</link>
        <guid isPermaLink="true">https://www.grassfish.net/2018/11/04/lvm-resize-log/</guid>
        
        <category>Linux</category>
        
        
      </item>
    
      <item>
        <title>智能卡安全之 M1 卡破解</title>
        <description>&lt;blockquote&gt;
  &lt;p&gt;之所以起这个标题，是想有朝一日可以写成一个系列。由于目前手里只有一张未加密的 M1（MIFARE Classic 1K）卡，因此本文仅包含对 M1 卡的破解。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;0x00-智能卡概况&quot;&gt;0x00 智能卡概况&lt;/h1&gt;

&lt;p&gt;M1 卡可分为 16 个扇区，每个扇区可分为 4 个段，每个段为 16 字节（即 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1K = 16 * 4 * 16B&lt;/code&gt;）。&lt;/p&gt;

&lt;p&gt;其中每个扇区的最后一段包含独立密钥，布局为：Key A(6B) + 控制位(4B) + Key B(6B)&lt;/p&gt;

&lt;p&gt;M1 卡的整体布局如下：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;00000000: 56b1 ce83 aa08 0400 6263 6465 6667 6869  V.......bcdefghi
00000010: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000020: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000030: ffff ffff ffff ff07 8069 ffff ffff ffff  .........i......
00000040: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000050: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000060: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000070: ffff ffff ffff ff07 8069 ffff ffff ffff  .........i......
00000080: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000090: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000000a0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000000b0: ffff ffff ffff ff07 8069 ffff ffff ffff  .........i......
000000c0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000000d0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000000e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000000f0: ffff ffff ffff ff07 8069 ffff ffff ffff  .........i......
00000100: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000110: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000120: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000130: ffff ffff ffff ff07 8069 ffff ffff ffff  .........i......
00000140: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000150: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000160: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000170: ffff ffff ffff ff07 8069 ffff ffff ffff  .........i......
00000180: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000190: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001a0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001b0: ffff ffff ffff ff07 8069 ffff ffff ffff  .........i......
000001c0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001d0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001f0: ffff ffff ffff ff07 8069 ffff ffff ffff  .........i......
00000200: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000210: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000220: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000230: ffff ffff ffff ff07 8069 ffff ffff ffff  .........i......
00000240: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000250: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000260: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000270: ffff ffff ffff ff07 8069 ffff ffff ffff  .........i......
00000280: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000290: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000002a0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000002b0: ffff ffff ffff ff07 8069 ffff ffff ffff  .........i......
000002c0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000002d0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000002e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000002f0: ffff ffff ffff ff07 8069 ffff ffff ffff  .........i......
00000300: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000310: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000320: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000330: ffff ffff ffff ff07 8069 ffff ffff ffff  .........i......
00000340: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000350: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000360: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000370: ffff ffff ffff ff07 8069 ffff ffff ffff  .........i......
00000380: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000390: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000003a0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000003b0: ffff ffff ffff ff07 8069 ffff ffff ffff  .........i......
000003c0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000003d0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000003e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000003f0: ffff ffff ffff ff07 8069 ffff ffff ffff  .........i......
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;我们从淘宝上可以买到的白卡大致分为一下几种：&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;类型&lt;/th&gt;
      &lt;th&gt;说明&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;M1&lt;/td&gt;
      &lt;td&gt;普通 IC 卡，除 0 扇区不可修改，其他扇区可重复擦写&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;UID&lt;/td&gt;
      &lt;td&gt;普通 IC 复制卡（Chinese clones），可重复擦写所有扇区&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;CUID&lt;/td&gt;
      &lt;td&gt;用于绕过系统对 UID 卡的拦截&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;FUID&lt;/td&gt;
      &lt;td&gt;用于绕过系统对 CUID 卡的拦截，0 扇区写入一次后变成 M1 卡&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;UFUID&lt;/td&gt;
      &lt;td&gt;UID 和 FUID 的合成卡，需要封卡操作&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h1 id=&quot;0x01-工具准备&quot;&gt;0x01 工具准备&lt;/h1&gt;

&lt;p&gt;出于省钱的考虑采用的方案为：NXP 自家的 PN532 NFC/RFID v3 模块 + CH340 USB 转 TTL 模块&lt;/p&gt;

&lt;p&gt;硬件：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;PN532&lt;/li&gt;
  &lt;li&gt;CH340&lt;/li&gt;
  &lt;li&gt;UID 白卡若干&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;软件：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;libnfc&lt;/li&gt;
  &lt;li&gt;mfoc&lt;/li&gt;
  &lt;li&gt;mfcuk&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;M1（MIFARE Classic 1K）卡是我们日常生活中经常接触到的智能卡之一，本次破解为使用 UID 卡对博主小区的 M1 门禁卡进行复制（小区门禁是检测 0 扇区的数据）。&lt;/p&gt;

&lt;p&gt;由于 Linux 内核自 2.6 之后默认添加了对 CH340/CH341 芯片的驱动支持，将 PN532 连接好，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libnfc&lt;/code&gt; 安装完成后，即可使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nfc-list&lt;/code&gt; 检测系统是否成功识别 NFC 设备。若无法识别可尝试在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/nfc/libnfc.conf&lt;/code&gt; 中设置如下选项以自动检测设备：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;allow_autoscan = true
allow_intrusive_scan = true
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;0x02-破解扇区密钥&quot;&gt;0x02 破解扇区密钥&lt;/h1&gt;

&lt;p&gt;首先使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mfoc&lt;/code&gt; 尝试导出扇区转储：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo mfoc -O mycard.mfd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;该工具会使用内嵌的默认密码字典尝试解密各扇区，若出现如下输出则说明该卡需要破解：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Try to authenticate to all sectors with default keys...
Symbols: '.' no key found, '/' A key found, '\' B key found, 'x' both keys found
[Key: ffffffffffff] -&amp;gt; [................]
[Key: a0a1a2a3a4a5] -&amp;gt; [................]
[Key: d3f7d3f7d3f7] -&amp;gt; [................]
[Key: 000000000000] -&amp;gt; [................]
[Key: b0b1b2b3b4b5] -&amp;gt; [................]
[Key: 4d3a99c351dd] -&amp;gt; [................]
[Key: 1a982c7e459a] -&amp;gt; [................]
[Key: aabbccddeeff] -&amp;gt; [................]
[Key: 714c5c886e97] -&amp;gt; [................]
[Key: 587ee5f9350f] -&amp;gt; [................]
[Key: a0478cc39091] -&amp;gt; [................]
[Key: 533cb6c723f6] -&amp;gt; [................]
[Key: 8fd0a4f256e9] -&amp;gt; [................]
 
Sector 00 -  UNKNOWN_KEY [A]  Sector 00 -  UNKNOWN_KEY [B]  
Sector 01 -  UNKNOWN_KEY [A]  Sector 01 -  UNKNOWN_KEY [B]  
Sector 02 -  UNKNOWN_KEY [A]  Sector 02 -  UNKNOWN_KEY [B]  
Sector 03 -  UNKNOWN_KEY [A]  Sector 03 -  UNKNOWN_KEY [B]  
Sector 04 -  UNKNOWN_KEY [A]  Sector 04 -  UNKNOWN_KEY [B]  
Sector 05 -  UNKNOWN_KEY [A]  Sector 05 -  UNKNOWN_KEY [B]  
Sector 06 -  UNKNOWN_KEY [A]  Sector 06 -  UNKNOWN_KEY [B]  
Sector 07 -  UNKNOWN_KEY [A]  Sector 07 -  UNKNOWN_KEY [B]  
Sector 08 -  UNKNOWN_KEY [A]  Sector 08 -  UNKNOWN_KEY [B]  
Sector 09 -  UNKNOWN_KEY [A]  Sector 09 -  UNKNOWN_KEY [B]  
Sector 10 -  UNKNOWN_KEY [A]  Sector 10 -  UNKNOWN_KEY [B]  
Sector 11 -  UNKNOWN_KEY [A]  Sector 11 -  UNKNOWN_KEY [B]  
Sector 12 -  UNKNOWN_KEY [A]  Sector 12 -  UNKNOWN_KEY [B]  
Sector 13 -  UNKNOWN_KEY [A]  Sector 13 -  UNKNOWN_KEY [B]  
Sector 14 -  UNKNOWN_KEY [A]  Sector 14 -  UNKNOWN_KEY [B]  
Sector 15 -  UNKNOWN_KEY [A]  Sector 15 -  UNKNOWN_KEY [B]  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;MFCUK（MiFare Classic Universal toolKit） 是一款基于 darkside 攻击原理破解全加密 M1 卡的开源软件，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mfcuk&lt;/code&gt; 通过算法的漏洞破解出第一个 Key，如果某个扇区的 Key 被破解出来，就可以再使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mfoc&lt;/code&gt; 工具使用 nested authentication 攻击破解其他扇区的密码：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo mfcuk -C -R {} -s 250 -S 250

说明：
{} 替换为待破解的扇区号，也可使用切片指定范围 0:A
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;0x03-导出扇区转储&quot;&gt;0x03 导出扇区转储&lt;/h1&gt;

&lt;p&gt;使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mfoc&lt;/code&gt; 尝试以默认密钥导出扇区转储：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo mfoc -O mycard.mfd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;0x04-写入新卡&quot;&gt;0x04 写入新卡&lt;/h1&gt;

&lt;p&gt;使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nfc-mfclassic&lt;/code&gt;（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libnfc&lt;/code&gt; 内置）将转储文件写入白卡：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo nfc-mfclassic W a mycard.mfd mycard.mfd f

说明：
W 为可写入 0 扇区（UID 卡）
a 为使用 Key A 解密，遇错时退出
第一个 mycard.mfd 为待写入的转储文件
第二个 mycard.mfd f 为包含密钥的转储文件
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;参考资料&quot;&gt;参考资料&lt;/h1&gt;

&lt;ol&gt;
  &lt;li&gt;https://mp.weixin.qq.com/s?__biz=MzI5MDQ2NjExOQ==&amp;amp;mid=2247488354&amp;amp;idx=1&amp;amp;sn=be1205869e1be6bf5df3b3f2132d2969&lt;/li&gt;
  &lt;li&gt;https://fanzheng.org/archives/30&lt;/li&gt;
  &lt;li&gt;https://zohead.com/archives/copy-mifare-classic/&lt;/li&gt;
&lt;/ol&gt;
</description>
        <pubDate>Tue, 30 Oct 2018 13:30:00 +0000</pubDate>
        <link>https://www.grassfish.net/2018/10/30/mifare-classic-crack/</link>
        <guid isPermaLink="true">https://www.grassfish.net/2018/10/30/mifare-classic-crack/</guid>
        
        <category>无线安全</category>
        
        
      </item>
    
      <item>
        <title>博客部署优化实践</title>
        <description>&lt;h1 id=&quot;0x00-概述&quot;&gt;0x00 概述&lt;/h1&gt;

&lt;p&gt;本博客目前采用了两个国内外较为出名的代码托管平台提供的 Pages 服务，具体方案为：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;境外线路 -&amp;gt; Github Pages&lt;/li&gt;
  &lt;li&gt;国内线路 -&amp;gt; Coding Pages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Github 和 Coding 都可以使用 Let’s Encrypt 提供的 SSL/TLS 证书自动部署服务，且支持开启 HSTS。同时，对于当前方案的考虑是，一方面可以一定程度上地优化国内外用户的访问速度，另一方面还可以解决百度爬虫无法收录 Github Pages 的问题。&lt;/p&gt;

&lt;h1 id=&quot;0x01-远程与本地配置&quot;&gt;0x01 远程与本地配置&lt;/h1&gt;

&lt;p&gt;DNS 解析设置如下：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/blog-deploy-optimize/01.png&quot; alt=&quot;01.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Github Pages 及 Coding Pages 的具体搭建过程此处略过，添加自定义域名并开启 HTTPS 即可。&lt;/p&gt;

&lt;p&gt;Git 远程仓库配置如下，此处添加了 all 远程仓库，并分别设置了 Github 和 Coding 的仓库地址。如此以来只用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git push&lt;/code&gt; 就能一次性同步更新两个仓库了：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;// 添加一个名为 all 的远程仓库，并设置仓库的原始 url
git remote add all git@github.com:gsfish/gsfish.github.io.git
// 为 all 添加两个 pushurl
git remote set-url --add --push all git@github.com:gsfish/gsfish.github.io.git
git remote set-url --add --push all git@git.coding.net:gsfish/gsfish.coding.me.git
// 将 git push 的上游设置为 all 的 master 分支
git push -u all master
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;0x02-coding-重定向问题&quot;&gt;0x02 Coding 重定向问题&lt;/h1&gt;

&lt;p&gt;使用之后发现了一个问题。以下为原本使用 Github Pages 时返回的相应，是一个 301 跳转，可直接跳转至博客页面：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;HTTP/2 301 
server: GitHub.com
content-type: text/html
location: http://www.grassfish.net/
x-github-request-id: BAAC:6D17:24C5032:2834EAF:5B091C90
accept-ranges: bytes
date: Sat, 26 May 2018 09:18:25 GMT
via: 1.1 varnish
age: 2513
x-served-by: cache-lax8624-LAX
x-cache: HIT
x-cache-hits: 1
x-timer: S1527326306.892833,VS0,VE1
vary: Accept-Encoding
x-fastly-request-id: 6b5ccd78a634d30cdb150750115c7a77d32d0229
content-length: 178

&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;&amp;lt;title&amp;gt;301 Moved Permanently&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;
&amp;lt;body bgcolor=&quot;white&quot;&amp;gt;
&amp;lt;center&amp;gt;&amp;lt;h1&amp;gt;301 Moved Permanently&amp;lt;/h1&amp;gt;&amp;lt;/center&amp;gt;
&amp;lt;hr&amp;gt;&amp;lt;center&amp;gt;nginx&amp;lt;/center&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;而以下为首次访问 Coding Pages 时返回的响应内容，是一个 302 跳转：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;HTTP/2 302 
location: https://coding.net/pages/waiting?redirect=https%3A%2F%2Fwww.grassfish.net%2F
server: Coding Pages
set-cookie: splash=1; Domain=www.grassfish.net; Expires=Sun, 27 May 2018 08:54:27 GMT; HttpOnly
vary: Accept-Encoding
content-type: text/html; charset=utf-8
content-length: 99
date: Sat, 26 May 2018 08:54:27 GMT

&amp;lt;a href=&quot;https://coding.net/pages/waiting?redirect=https%3A%2F%2Fwww.grassfish.net%2F&quot;&amp;gt;Found&amp;lt;/a&amp;gt;.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;对于 301、302 跳转之间的区别可以参考&lt;a href=&quot;http://veryyoung.me/blog/2015/08/24/difference-between-301-and-302.html&quot;&gt;这篇博客&lt;/a&gt;，比较重要的一点是对于 301 跳转浏览器是可以缓存的。根据该 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;location&lt;/code&gt; 重定向的内容，Coding 会先放 5 秒钟的广告，然后才跳转到正常的博客页面。同时会设置一个 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;splash=1&lt;/code&gt; 的 Cookie 以记录当前用户的阅览状态。&lt;/p&gt;

&lt;p&gt;毕竟是免费的东西，而自己又懒得维护一个独立的服务器，只能说有点失望咯。下一步考虑只将百度的线路解析至 Coding 用于爬虫收录，默认线路还是解析至 Github Pages。&lt;/p&gt;

&lt;h1 id=&quot;0x03-最终方案&quot;&gt;0x03 最终方案&lt;/h1&gt;

&lt;p&gt;于是乎，现已成功更改为上述方案。本来想把 DNS 服务器改为 Cloudfare 的，顺便使用 CDN，不过 Cloudfare 的免费版并不支持国内外分线路解析（需要 Enterprise），因此作罢。&lt;/p&gt;

&lt;h1 id=&quot;参考资料&quot;&gt;参考资料&lt;/h1&gt;

&lt;ol&gt;
  &lt;li&gt;http://www.atjiang.com/coding.net-pages-as-github-pages-mirror-for-baidu/&lt;/li&gt;
  &lt;li&gt;https://stackoverflow.com/questions/14290113/git-pushing-code-to-two-remotes&lt;/li&gt;
&lt;/ol&gt;
</description>
        <pubDate>Sat, 26 May 2018 09:00:00 +0000</pubDate>
        <link>https://www.grassfish.net/2018/05/26/pages-deploy-optimize/</link>
        <guid isPermaLink="true">https://www.grassfish.net/2018/05/26/pages-deploy-optimize/</guid>
        
        <category>运维</category>
        
        
      </item>
    
      <item>
        <title>Burp Suite 学习总结</title>
        <description>&lt;blockquote&gt;
  &lt;p&gt;最近在重新学习使用 Burp Suite，此物确实乃 Web 安全测试的一大利器。总结了一些较有用设置选项，可用于 SSL 抓包等。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;0x00-burp-suite-工作流程&quot;&gt;0x00 Burp Suite 工作流程&lt;/h1&gt;

&lt;p&gt;&lt;img src=&quot;/img/burpsuite-summary/01.png&quot; alt=&quot;01.png&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;0x01-设置选项&quot;&gt;0x01 设置选项&lt;/h1&gt;

&lt;h2 id=&quot;proxy-标签页&quot;&gt;Proxy 标签页&lt;/h2&gt;

&lt;p&gt;参考官方文档 &lt;a href=&quot;https://portswigger.net/burp/help/proxy_options&quot;&gt;Burp Proxy Options&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;proxy-listeners&quot;&gt;Proxy Listeners&lt;/h3&gt;

&lt;h4 id=&quot;1-binding&quot;&gt;1 Binding&lt;/h4&gt;

&lt;p&gt;IP 和端口绑定设置，绑定 IP 地址分仅本地回路、所有接口、指定地址三种模式。&lt;/p&gt;

&lt;h4 id=&quot;2-request-handling&quot;&gt;2 Request handling&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;/img/burpsuite-summary/02.png&quot; alt=&quot;02.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Redict to host&lt;/code&gt;：&lt;/p&gt;

&lt;p&gt;将 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;request&lt;/code&gt; 转发到指定主机。若该主机与 Host 不同可添加一条 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Match and Replace&lt;/code&gt; 配置。&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Force use of SSL&lt;/code&gt;：&lt;/p&gt;

&lt;p&gt;强制使用 SSL。适用于开启了 HTST 的站点（在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Response Modification&lt;/code&gt; 中对 HTTPS 进行了降级，或使用了 ssltrip）。&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Support invisiable proxying&lt;/code&gt;：&lt;/p&gt;

&lt;p&gt;启用透明代理，详情参考官方文档 &lt;a href=&quot;https://portswigger.net/burp/help/proxy_options_invisible&quot;&gt;Burp Proxy: Invisible Proxying&lt;/a&gt;。适用于 non-proxy-aware 客户端（通过改本地 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hosts&lt;/code&gt; 文件，或 DLL 劫持等方式进行的代理）。&lt;/p&gt;

&lt;p&gt;默认从请求的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Host&lt;/code&gt; 字段中识别目标主机并转发，若使用了改 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hosts&lt;/code&gt; 的方式进行代理，则需在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Project options - Connections - Hostname Resolution&lt;/code&gt; 中添加该域名的正确记录；若无法识别 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Host&lt;/code&gt; 字段，则需在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Listioners&lt;/code&gt; 中设置上述的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Redict to host&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;对于 SSL 流量，若客户端会对服务端进行验证，则会使用该 hostname 生成证书；若不进行认证，则使用自签名证书。若设置了 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Redict to host&lt;/code&gt;，则可在该 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Listener&lt;/code&gt; 设置对应 hostname 的 CA-signed 证书；若代理的请求中含有多个目标域名，则可设置多个虚拟网卡与 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Listener&lt;/code&gt; 并分别生成证书。&lt;/p&gt;

&lt;h4 id=&quot;3-certificate&quot;&gt;3 Certificate&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;/img/burpsuite-summary/03.png&quot; alt=&quot;03.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;self-signed certificate&lt;/code&gt;：
CA 的根证书、使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;openssl&lt;/code&gt; 生成的证书为自签名证书，客户端不信任（内置 CA 除外）。&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CA-signed certificate&lt;/code&gt;：&lt;/p&gt;

&lt;p&gt;由 CA 颁发的证书为签名证书。&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CA-signed certificate with specific hostname&lt;/code&gt;：&lt;/p&gt;

&lt;p&gt;适用于使用了 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;invisiable proxying&lt;/code&gt; 或 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Redict to host&lt;/code&gt; 的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Listener&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;custom certificate&lt;/code&gt;：&lt;/p&gt;

&lt;p&gt;官网有使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;openssl&lt;/code&gt; 生成该证书教程 &lt;a href=&quot;https://portswigger.net/burp/help/proxy_options#listeners_creatingcert&quot;&gt;Creating a Custom CA Certificate&lt;/a&gt;&lt;/p&gt;

&lt;h4 id=&quot;4-ssl-pass-through&quot;&gt;4 SSL Pass Through&lt;/h4&gt;

&lt;p&gt;对于列表中所设置的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;域名&lt;/code&gt; / &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IP&lt;/code&gt; / &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;端口&lt;/code&gt; 范围内的 SSL 流量不进行拦截。适用于 SSL 报错影响正常连接、无法消除的场景，例如移动端 APP 产生的请求。&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;automatically add entries on client SSL negotiation failure&lt;/code&gt;：&lt;/p&gt;

&lt;p&gt;若 SSL 连接建立失败，则自动将该目标加入到列表中（下次忽略）。&lt;/p&gt;

&lt;h2 id=&quot;intruder-标签页&quot;&gt;Intruder 标签页&lt;/h2&gt;

&lt;p&gt;Intruder 在原始请求数据的基础上，通过修改各种请求参数，以获取不同的请求应答。每一次请求中，Intruder 通常会携带一个或多个 Payload，在不同的位置进行攻击重放，通过应答数据的比对分析来获得需要的特征数据。&lt;/p&gt;

&lt;h3 id=&quot;positions&quot;&gt;Positions&lt;/h3&gt;

&lt;h4 id=&quot;1-attack-type&quot;&gt;1 Attack type&lt;/h4&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Sniper&lt;/code&gt;：&lt;/p&gt;

&lt;p&gt;它使用一组 Payload 集合，依次替换 Payload 位置上（一次攻击只能使用一个 Payload 位置）被 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;§&lt;/code&gt; 标志的文本（而没有被 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;§&lt;/code&gt; 标志的文本将不受影响），对服务器端进行请求，通常用于测试请求参数是否存在漏洞。&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Battering ram&lt;/code&gt;：&lt;/p&gt;

&lt;p&gt;它使用单一的 Payload 集合，依次替换 Payload 位置上被 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;§&lt;/code&gt; 标志的文本（而没有被 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;§&lt;/code&gt; 标志的文本将不受影响），对服务器端进行请求，与 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Sniper&lt;/code&gt; 模式的区别在于，如果有多个参数且都为 Payload 位置标志时，使用的 Payload 值是相同的，而 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Sniper&lt;/code&gt; 模式只能使用一个 Payload 位置标志。&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Pitchfork&lt;/code&gt;：&lt;/p&gt;

&lt;p&gt;它可以使用多组 Payload 集合，在每一个不同的 Payload 标志位置上（最多 20 个），遍历所有的 Payload。举例来说，如果有两个 Payload 标志位置，第一个 Payload 值为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;B&lt;/code&gt;，第二个 Payload 值为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;D&lt;/code&gt;，则发起攻击时，将共发起两次攻击，第一次使用的 Payload 分别为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A&lt;/code&gt; 和&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C&lt;/code&gt;，第二次使用的 Payload 分别为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;B&lt;/code&gt; 和&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;D&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Cluster bomb&lt;/code&gt;：&lt;/p&gt;

&lt;p&gt;它可以使用多组 Payload 集合，在每一个不同的 Payload 标志位置上（最多 20 个），依次遍历所有的 Payload。它与 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Pitchfork&lt;/code&gt; 模式的主要区别在于，所发送请求中的 Payload 组合为各不同位置 Payload 值的笛卡尔乘积。举例来说，如果有两个 Payload 标志位置，第一个 Payload 值为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;B&lt;/code&gt;，第二个 Payload 值为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;D&lt;/code&gt;，则发起攻击时，将共发起四次攻击，第一次使用的 Payload 分别为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C&lt;/code&gt;，第二次使用的 Payload 分别为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;D&lt;/code&gt;，第三次使用的 Payload 分别为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;B&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C&lt;/code&gt;，第四次使用的 Payload 分别为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;B&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;D&lt;/code&gt;。&lt;/p&gt;

&lt;h3 id=&quot;payloads&quot;&gt;Payloads&lt;/h3&gt;

&lt;h4 id=&quot;1-payloads-type&quot;&gt;1 Payloads type&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;/img/burpsuite-summary/04.png&quot; alt=&quot;04.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Simple list&lt;/code&gt;：&lt;/p&gt;

&lt;p&gt;最简单的 Payload 类型，通过配置一个字符串列表作为 Payload，也可以手工添加字符串列表或从文件加载字符串列表。在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Add from list...&lt;/code&gt; 中可以添加内置的 Payload 列表，包括 XSS、SQL注入、数字、大小写字母、用户名、密码和目录名等等。&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Runtime file&lt;/code&gt;：&lt;/p&gt;

&lt;p&gt;指定文件，作为相对应 Payload 位置上的 Payload 列表。&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Custom iterator&lt;/code&gt;：&lt;/p&gt;

&lt;p&gt;一共可指定 8 个 position，每个 position 可以指定 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Simple list&lt;/code&gt; 类型的 Payload，然后所有指定过的 position 进行笛卡尔积，生成最终的 Payload 列表。&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Character substitution&lt;/code&gt;：&lt;/p&gt;

&lt;p&gt;对预定义的字符串进行替换后生成新的 Payload。&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Case modification&lt;/code&gt;：&lt;/p&gt;

&lt;p&gt;对预定义的字符串，按照大小写规则，进行替换。&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Recursive grep&lt;/code&gt;：&lt;/p&gt;

&lt;p&gt;适用于所发送的 Payload 需要提供部分服务端响应的内容（如 CSRF token 等）的场景。对响应内容的提取规则可在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Options&lt;/code&gt; -&amp;gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Grep - Extract&lt;/code&gt; 中设置。&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Illegal Unicode&lt;/code&gt;：&lt;/p&gt;

&lt;p&gt;用于基于原始字符串，并由多种规则生成不合法的 Unicode Payloads 绕过基于字符匹配的防御机制。&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Character blocks&lt;/code&gt;：&lt;/p&gt;

&lt;p&gt;用于缓冲区溢出或边界测试。将根据设置的长度、增长步长产生不同大小的字符块 Payload。&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Number&lt;/code&gt;、&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Dates&lt;/code&gt;：&lt;/p&gt;

&lt;p&gt;顾名思义，生成数字、日期形式的 Payload。&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Brute forcer&lt;/code&gt;：&lt;/p&gt;

&lt;p&gt;使用预定字符，基于长度设置生成其全排列作为 Payload。&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Null payloads&lt;/code&gt;：&lt;/p&gt;

&lt;p&gt;不产生任何 Payload，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Intruder&lt;/code&gt; 将重放指定次数请求。可用于维持 Session 或对具有竞争条件漏洞的应用进行攻击。&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Character frobber&lt;/code&gt;：&lt;/p&gt;

&lt;p&gt;依次修改指定字符串在每个字符位置的值，每次都是在原字符上递增一个该字符的 ASCII 码。可用于测试请求令牌中的不同字符对应用功能的影响。&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Bit flipper&lt;/code&gt;：&lt;/p&gt;

&lt;p&gt;对预设的 Payload 原始值，按照比特位，依次进行修改。&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Username generator&lt;/code&gt;：&lt;/p&gt;

&lt;p&gt;用于基于指定规则，自动生成用户名和 Email 帐号。&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ECB block shuffler&lt;/code&gt;：&lt;/p&gt;

&lt;p&gt;用于测试基于 ECB 加密模式的请求数据，通过改变分组数据的位置方式来验证应用程序是否易受到攻击。&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Extension-generated&lt;/code&gt;：&lt;/p&gt;

&lt;p&gt;基于 Burp 插件来生成 Payload，因此使用前必须安装配置 Burp 插件。在插件中注册一个Intruder payload 生成器，供此处调用。&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Copy other payload&lt;/code&gt;：&lt;/p&gt;

&lt;p&gt;将其他位置的参数复制到当前 Payload 位置上，作为新的 Payload 值，通常适用于多个参数的请求消息中。&lt;/p&gt;

&lt;h2 id=&quot;其他&quot;&gt;其他&lt;/h2&gt;

&lt;p&gt;更多的设置选项在 &lt;a href=&quot;https://www.gitbook.com/book/t0data/burpsuite&quot;&gt;这篇文档&lt;/a&gt; 中有很详细的记载。不过部分内容感觉是机翻的，阅读起来有些问题，还是建议参考官方文档。&lt;/p&gt;

&lt;h1 id=&quot;参考资料&quot;&gt;参考资料&lt;/h1&gt;

&lt;ol&gt;
  &lt;li&gt;https://www.gitbook.com/book/t0data/burpsuite&lt;/li&gt;
  &lt;li&gt;https://portswigger.net/burp/help/contents&lt;/li&gt;
&lt;/ol&gt;
</description>
        <pubDate>Mon, 14 May 2018 07:00:00 +0000</pubDate>
        <link>https://www.grassfish.net/2018/05/14/burpsuite-notes/</link>
        <guid isPermaLink="true">https://www.grassfish.net/2018/05/14/burpsuite-notes/</guid>
        
        <category>Web安全</category>
        
        <category>渗透</category>
        
        
      </item>
    
      <item>
        <title>Django 性能优化实践</title>
        <description>&lt;h1 id=&quot;0x00-运行环境&quot;&gt;0x00 运行环境&lt;/h1&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;运行环境&lt;/th&gt;
      &lt;th&gt;环境配置&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;操作系统&lt;/td&gt;
      &lt;td&gt;Ubuntu 16.04.3 LTS&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;CPU&lt;/td&gt;
      &lt;td&gt;Intel(R) Xeon(R) CPU E5-26xx v3 双核 2.0GHz&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;内存&lt;/td&gt;
      &lt;td&gt;2G&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;编程语言&lt;/td&gt;
      &lt;td&gt;Python 3.5.2&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;后台框架&lt;/td&gt;
      &lt;td&gt;Django 2.0.2&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;压测工具&lt;/td&gt;
      &lt;td&gt;ApacheBench 2.3&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h1 id=&quot;0x01-并发访问&quot;&gt;0x01 并发访问&lt;/h1&gt;

&lt;h2 id=&quot;runserver&quot;&gt;runserver&lt;/h2&gt;

&lt;p&gt;由于 Django 并没有提供高性能的 server 端来处理连接，所以一般不建议使用该命令在生产环境中部署。&lt;/p&gt;

&lt;h2 id=&quot;gunicorn&quot;&gt;Gunicorn&lt;/h2&gt;

&lt;p&gt;Django 在&lt;a href=&quot;http://docs.gunicorn.org/en/latest/design.html#how-many-workers&quot;&gt;官方文档&lt;/a&gt;中提到过 Worker 数的一个推荐设置 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(2 x $num_cores) + 1&lt;/code&gt;。因此采用了以下方案，使用 Nginx 反向代理（项目的 Web API 仍会用到一些静态资源），Django 负责实现 WSGI，并由 Gunicorn pre-fork 出 5 个 Worker，每个 Worker 通过 gevent 异步处理事务：&lt;/p&gt;

&lt;p&gt;nginx + gunicorn (gevent, 5 worker)&lt;/p&gt;

&lt;h2 id=&quot;压力测试&quot;&gt;压力测试&lt;/h2&gt;

&lt;p&gt;ApacheBench：&lt;/p&gt;

&lt;p&gt;ab 命令会创建很多的并发访问线程，模拟多个访问者同时对某一 URL 地址进行访问。它的测试目标是基于 URL 的，因此，既可以用来测试 Apache 的负载压力，也可以测试 nginx、lighthttp、tomcat、IIS 等其它 Web Server的压力。&lt;/p&gt;

&lt;p&gt;ab 命令对发出负载的计算机要求很低，既不会占用很高 CPU，也不会占用很多内存，但却会给目标服务器造成巨大的负载，其原理类似 CC 攻击。自己测试使用也须注意，否则一次上太多的负载，可能造成目标服务器因资源耗完，严重时甚至导致死机。&lt;/p&gt;

&lt;p&gt;测试对象为项目中涉及 IO 操作较多的一个面板展示接口。为了降低网络延迟对测试结果的影响，采用对本地地址 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;127.0.0.1&lt;/code&gt; 压测的方式进行。另外由于软件本身的限制，请求数最大只能为 50000，因此两次测试耗时各不相同。&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ab -t 60 -c 100 -p params.txt -m post -T application/x-www-form-urlencoded -v 1 http://127.0.0.1:8000/api/v1/dashboard/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;使用 runserver：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Server Software:        WSGIServer/0.2
Server Hostname:        127.0.0.1
Server Port:            8000

# 测试的页面
Document Path:          /api/v1/dashboard/
# 页面大小
Document Length:        1748 bytes

# 测试的并发数
Concurrency Level:      100
# 整个测试持续的时间
Time taken for tests:   60.075 seconds
# 完成的请求数量
Complete requests:      1071
# 失败的请求数量
Failed requests:        0
# 整个过程中的网络传输量
Total transferred:      2108891 bytes
# 整个过程中的 HTML 内容传输量
Total body sent:        266444
HTML transferred:       1872108 bytes
# 最重要的指标之一，相当于 LR 中的每秒事务数，后面括号中的 mean 表示这是一个平均值
Requests per second:    17.83 [#/sec] (mean)
# 最重要的指标之二，相当于 LR 中的平均事务响应时间，后面括号中的 mean 表示这是一个平均值
Time per request:       5609.283 [ms] (mean)
# 每个连接请求实际运行时间的平均值
# 对于并发请求，CPU 实际上并不是同时处理的，而是按照每个请求获得的时间片逐个轮转处理的，所以基本上第一个 Time per request 时间约等于第二个 Time per request 时间乘以并发请求数。
Time per request:       56.093 [ms] (mean, across all concurrent requests)
# 平均每秒网络上的流量，可以帮助排除是否存在网络流量过大导致响应时间延长的问题
Transfer rate:          34.28 [Kbytes/sec] received
                        4.33 kb/s sent
                        38.61 kb/s total

# 网络上消耗的时间的分解，各项数据的具体算法还不是很清楚
Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0 1458 3611.3      0   31076
Processing:  1563 2536 1105.4   2372   29195
Waiting:     1545 2499 1104.0   2335   29174
Total:       1563 3995 3820.4   2901   36210

# 整个场景中所有请求的响应情况，为响应时间的一个分布率。其中 50％ 的用户响应时间小于 2901ms，66％ 的用户响应时间小于 3409ms，最大的响应时间小于 36210ms
Percentage of the requests served within a certain time (ms)
  50%   2901
  66%   3409
  75%   3872
  80%   4661
  90%   5674
  95%   9734
  98%  17420
  99%  17766
 100%  36210 (longest request)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;使用 Gunicorn：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Server Software:        nginx/1.10.3
Server Hostname:        127.0.0.1
Server Port:            8000

# 测试的页面
Document Path:          /api/v1/dashboard/
# 页面大小
Document Length:        182 bytes

# 测试的并发数
Concurrency Level:      100
# 整个测试持续的时间
Time taken for tests:   2.219 seconds
# 完成的请求数量
Complete requests:      50000
# 失败的请求数量
Failed requests:        0
Non-2xx responses:      50000
# 整个过程中的网络传输量
Total transferred:      17150000 bytes
# 整个过程中的 HTML 内容传输量
Total body sent:        11800000
HTML transferred:       9100000 bytes
# 最重要的指标之一，相当于 LR 中的每秒事务数
Requests per second:    22532.28 [#/sec] (mean)
# 最重要的指标之二，相当于 LR 中的平均事务响应时间
Time per request:       4.438 [ms] (mean)
# 每个连接请求实际运行时间的平均值
Time per request:       0.044 [ms] (mean, across all concurrent requests)
# 平均每秒网络上的流量，可以帮助排除是否存在网络流量过大导致响应时间延长的问题
Transfer rate:          7547.43 [Kbytes/sec] received
                        5192.99 kb/s sent
                        12740.42 kb/s total

# 网络上消耗的时间的分解，各项数据的具体算法还不是很清楚
Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    2   0.5      2       7
Processing:     1    2   0.7      2       9
Waiting:        0    2   0.6      2       9
Total:          2    4   0.8      4      11

# 整个场景中所有请求的响应情况，为响应时间的一个分布率
Percentage of the requests served within a certain time (ms)
  50%      4
  66%      4
  75%      4
  80%      4
  90%      5
  95%      5
  98%      8
  99%      9
 100%     11 (longest request)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;小结&quot;&gt;小结&lt;/h2&gt;

&lt;p&gt;根据 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Requests per second&lt;/code&gt; 可以见得，使用 Gunicorn (22532.28) 后在每秒的事务处理量上是默认 runserver (17.83) 的约 1264 倍。&lt;/p&gt;

&lt;h1 id=&quot;0x02-查询优化&quot;&gt;0x02 查询优化&lt;/h1&gt;

&lt;p&gt;// TODO&lt;/p&gt;

&lt;h1 id=&quot;0x03-进一步优化&quot;&gt;0x03 进一步优化&lt;/h1&gt;

&lt;h2 id=&quot;使用-redis-进行缓存&quot;&gt;使用 Redis 进行缓存&lt;/h2&gt;

&lt;p&gt;// TODO&lt;/p&gt;

&lt;h2 id=&quot;使用异步-worker-进行写库操作&quot;&gt;使用异步 Worker 进行写库操作&lt;/h2&gt;

&lt;p&gt;// TODO&lt;/p&gt;

&lt;h1 id=&quot;参考资料&quot;&gt;参考资料&lt;/h1&gt;

&lt;ol&gt;
  &lt;li&gt;http://python.jobbole.com/80836/&lt;/li&gt;
  &lt;li&gt;https://blog.csdn.net/qq_33339479/article/details/78873786&lt;/li&gt;
  &lt;li&gt;https://changchen.me/blog/20170503/django-performance-and-optimisation/&lt;/li&gt;
&lt;/ol&gt;
</description>
        <pubDate>Sat, 07 Apr 2018 13:30:00 +0000</pubDate>
        <link>https://www.grassfish.net/2018/04/07/django-optimization/</link>
        <guid isPermaLink="true">https://www.grassfish.net/2018/04/07/django-optimization/</guid>
        
        <category>Python</category>
        
        <category>Web开发</category>
        
        
      </item>
    
  </channel>
</rss>
