<!--
     The FreeBSD Documentation Project
     The FreeBSD Simplified Chinese Project

     Original Revision: 1.266
     $FreeBSD$
-->

<chapter id="security">
  <chapterinfo>
    <authorgroup>
      <author>
	<firstname>Matthew</firstname>
	<surname>Dillon</surname>
	<contrib>这一章的许多内容来自 security(7) 联机手册，其作者是 </contrib>
      </author>
    </authorgroup>
  </chapterinfo>

  <title>安全</title>
  <indexterm><primary>security</primary></indexterm>

  <sect1 id="security-synopsis">
    <title>概述</title>

    <para>这一章将对系统安全的基本概念进行介绍， 除此之外， 还将介绍一些好的习惯， 以及
      &os; 下的一些更深入的话题。 这章的许多内容对于一般的系统和 Internet
      安全也适用。 如今， Internet
      已经不再像以前那样是一个人人都愿意与您作好邻居的 <quote>友善</quote>
      的地方。 让系统更加安全， 将保护您的数据、 智力财产、 时间，
      以及其他很多东西不至于被入侵者或心存恶意的人所窃取。</para>

    <para>&os; 提供了一系列工具和机制来保证您系统和网络的完整和安全。</para>

    <para>&os;提供了大量的工具和机制来确保您的系统和网络的安全。</para>

    <para>读完这章，您将了解：</para>

    <itemizedlist>
      <listitem>
	<para>基本的 &os; 系统安全概念。</para>
      </listitem>

      <listitem>
	<para>&os; 中众多可用的密码学设施，例如
	  <acronym>DES</acronym> 和 <acronym>MD5</acronym>。</para>
      </listitem>

      <listitem>
	<para>如何设置一次性口令验证机制。</para>
      </listitem>

      <listitem>
	<para>如何配置 <acronym>TCP</acronym> Wrappers 以便与
	  <command>inetd</command> 配合使用。</para>
      </listitem>

      <listitem>
	<para>如何在 &os; 5.0 以前的版本上设置
	  <application>KerberosIV</application>。</para>
      </listitem>

      <listitem>
	<para>如何在 &os; 5.0 或更高版本上设置
	  <application>Kerberos5</application>。</para>
      </listitem>

      <listitem>
	<para>如何配置 IPsec 并在 &os;/&windows;
	机器之间建构 <acronym>VPN</acronym>。</para>
      </listitem>

      <listitem>
	<para>如何配置并使用 <application>OpenSSH</application>，以及 &os; 的 <acronym>SSH</acronym>
	  执行方式。</para>
      </listitem>

      <listitem>
	<para>系统 <acronym>ACL</acronym> 的概念，以及如何使用它们。</para>
      </listitem>

      <listitem>
	<para>如何使用 <application>Portaudit</application>
	  工具来审核从 Ports Collection 安装的第三方软件包的安全性。</para>
      </listitem>

      <listitem>
	<para>如何从 &os; 的安全公告中获得有用信息并采取相应措施。</para>
      </listitem>

      <listitem>
	<para>对于进程记帐功能的感性认识，
	  并了解如何在 &os; 中启用它。</para>
      </listitem>
    </itemizedlist>

    <para>在开始阅读这章之前，您需要：</para>

    <itemizedlist>
      <listitem>
	<para>理解基本的 &os; 和 Internet 概念。</para>
      </listitem>
    </itemizedlist>

    <para>其他安全方面的话题， 则贯穿本书的始终。
      例如， 强制性访问控制 (MAC) 在 <xref
      linkend="mac"> 中进行了介绍， 而 Internet 防火墙则在 <xref
      linkend="firewalls"> 中进行了讨论。</para>
  </sect1>

  <sect1 id="security-intro">
    <title>介绍</title>

    <para>安全是系统管理员自始至终的基本要求。 由于所有的 BSD &unix;
      多用户系统都提供了与生俱来的安全性， 因此建立和维护额外的安全机制，
      确保用户的 <quote>诚实</quote>
      可能也就是最需要系统管理员考虑的艰巨的工作了。
      机器的安全性取决于您设置的安全设施， 而许多安全方面的考虑，
      则会与人们使用计算机时的便利性相矛盾。 一般来说， &unix;
      系统能够胜任数目众多进程并发地处理各类任务，
      这其中的许多进程是以服务身份运行的 &mdash; 这意味着，
      外部实体能够与它们互联并产生会话交互。 如今的桌面系统，
      已经能够达到许多昔日的小型机甚至主机的性能，
      而随着这些计算机的联网和在更大范围内完成互联，
      安全也成为了一个日益严峻的课题。</para>

    <para>最好能够通过像
      <quote>洋葱</quote> 那样的分层方式来实现安全。 简而言之，
      方便的话， 应该建立尽可能多的安全层次，
      并小心地监视针对系统的各类入侵。 当然， 不应过分地构建安全机制，
      因为这样做可能会干扰甚至阻碍入侵检测，
      而后者正是安全机制中最为重要的一环。 例如，
      在所有操作系统的可执行文件上都设置 <literal>schg</literal> 标志
      (参见 &man.chflags.1;) 往往收效甚微， 因为这样做，
      尽管短时间内能够保护这些文件，
      但也阻止了闯入者进行那些易于检测的修改，
      这意味着您设置的安全机制可能根本就无法监测到攻击者。</para>

    <para>系统的安全也应能够应付各种形式的攻击， 这也包括那些使系统崩溃，
      或阻止其正常运转， 但并不试图窃取
      <username>root</username> 帐号 (<quote>破译 root</quote>)
      的攻击形式。 安全问题大体可分为以下几类：</para>

    <orderedlist>
      <listitem>
	<para>拒绝服务攻击。</para>
      </listitem>

      <listitem>
	<para>窃取其他用户的帐户。</para>
      </listitem>

      <listitem>
	<para> 通过可访问服务窃取root帐户。</para>
      </listitem>

      <listitem>
	<para>通过用户帐户窃取root帐户。</para>
      </listitem>

      <listitem>
	<para>建立后门。</para>
      </listitem>
    </orderedlist>

    <indexterm>
      <primary>DoS 攻击</primary>
      <see>拒绝服务攻击 (DoS)</see>
    </indexterm>
    <indexterm>
      <primary>安全</primary>
      <secondary>DoS 攻击</secondary>
      <see>拒绝服务攻击 (DoS)</see>
    </indexterm>
    <indexterm><primary>拒绝服务攻击 (DoS)</primary></indexterm>

    <para>拒绝式服务攻击是侵占机器所需资源的一种行为。
      通常， DoS 攻击采用暴力(brute-force)手段通过压倒性的流量来破坏服务器和网络栈，
      以使机器崩溃或无法使用。 某些 DoS 攻击则利用在网络栈中的错误，
      仅用一个简单的信息包就可以让机器崩溃， 这类情况通常只能通过给内核打补丁来修复。
      在一些不利的条件下， 对服务器的攻击能够被修复，
      只要适当地修改一下系统的选项来限制系统对服务器的负荷。
      顽强的网络攻击是很难对付的。 例如，一个欺骗性信息包的攻击，
      无法阻止入侵者切断您的系统与Internet的连接。
      它不会使您的机器死掉，但它会把Internet连接占满。</para>

    <indexterm>
      <primary>security</primary>
      <secondary>窃取用户帐户</secondary>
    </indexterm>

    <para>窃取用户帐户要比D.o.S.攻击更加普遍。
      许多系统管理员仍然在他们的服务器上运行着基本的
      <application>telnetd</application>，<application>rlogind</application>，
      <application>rshd</application> 和 <application>ftpd</application>
      服务。 这些服务在默认情况下不会以加密连接来操作。
      结果是如果您的系统有中等规模大小的用户群，
      在通过远程登录的方式登录到您系统的用户中， 一些人的口令会被人窃取。
      仔细的系统管理员会从那些成功登录系统的远程访问日志中寻找可疑的源地址。</para>



    <para>通常必须假定，如果一个入侵者已经访问到了一个用户的帐户，
      那么它就可能使自己成为 <username>root</username>。 然而，
      事实是在一个安全和维护做得很好的系统中，
      访问用户的帐户不一定会让入侵者成为 <username>root</username>。
      这个差别是很重要的，因为没有成为
      <username>root</username> 则入侵者通常是无法隐藏它的轨迹的， 而且，
      如果走运的话， 除了让用户的文件乱掉和系统崩溃之外，
      它不能做什么别的事情。 窃取用户帐户是很普遍的事情，
      因为用户往往不会对系统管理员的警告采取措施。</para>

    <indexterm>
      <primary>security</primary>
      <secondary>后门</secondary>
    </indexterm>

    <para>系统管理员必须牢牢记住，可能有许多潜在的方法会使他们机器上的
      <username>root</username> 用户受到威胁。入侵者可能知道
      <username>root</username> 的口令，而如果在以
      <username>root</username> 权限运行的服务器上找到一个缺陷 (bug)，
      就可以通过网络连接到那台服务器上达到目的；另外，
      一旦入侵者已经侵入了一个用户的帐户，
      可以在自己的机器上运行一个 suid-root 程序来发现服务器的漏洞，
      从而让他侵入到服务器并获取 <username>root</username>。
      攻击者找到了入侵一台机器上 <username>root</username> 的途径之后，
      他们就不再需要安装后门了。许多 <username>root</username>
      漏洞被发现并修正之后， 入侵者会想尽办法去删除日志来消除自己的访问痕迹，
      所以他们会安装后门。
      后门能给入侵者提供一个简单的方法来重新获取访问系统的 <username>root</username>
      权限， 但它也会给聪明的系统管理员一个检测入侵的简便方法。
      让入侵者无法安装后门事实上对您的系统安全是有害的，
      因为这样并不会修复那些侵入系统的入侵者所发现的新漏洞。</para>


    <para>安全的管理方法应当使用像 <quote>洋葱皮</quote> 一样多层次的方法来实现，
      这些措施可以按下面的方式进行分类：</para>

    <orderedlist>
      <listitem>
	<para>确保 <username>root</username> 和维护人员帐户的安全。</para>
      </listitem>

      <listitem>
	<para>确保 <username>root</username> &ndash; 以root用户权限运行的服务器和suid/sgid可执行程序的安全。</para>
      </listitem>

      <listitem>
	<para>确保用户帐户的安全。</para>
      </listitem>

      <listitem>
	<para>确保口令文件的安全。</para>
      </listitem>

      <listitem>
	<para>确保内核中核心组件、直接访问设备和文件系统的安全。</para>
      </listitem>

      <listitem>
	<para>快速检测系统中发生的不适当的变化。</para>
      </listitem>

      <listitem>
	<para>做个偏执狂。</para>
      </listitem>
    </orderedlist>

    <para>这一章的下一节将比较深入地讲述上面提到的每一个条目。</para>
  </sect1>

  <sect1 id="securing-freebsd">
    <title>确保 &os; 的安全</title>
    <indexterm>
      <primary>security</primary>
      <secondary>确保 &os; 的安全</secondary>
    </indexterm>

    <note>
      <title>命令与协议</title>
      <para>在这份文档中，我们使用
       <application>粗体</application> 来表示应用程序，
       并使用 <command>单倍距</command> 字体来表示命令。
       这样的排版区分能够有效地区分类似 ssh 这样的概念，
       因为它既可以表示命令，又可以表示协议。</para>
    </note>

    <para>接下来的几节中， 将介绍在这一章中 <link
        linkend="security-intro">前一节</link> 中所介绍的那些加强
      &os; 系统安全性的手段。</para>

    <sect2 id="securing-root-and-staff">
      <title>确保 <username>root</username> 和维护人员帐户的安全 </title>
      <indexterm>
        <primary><command>su</command></primary>
      </indexterm>

      <para>首先，如果您没有确保 <username>root</username> 帐户的安全，
	就没必要先劳神确保用户帐户的安全了。绝大多数系统都会指派一个口令给
	<username>root</username> 帐户。 我们的第一个假定是，口令
	<emphasis>总是</emphasis> 不安全的。 这并不意味着您要把口令删掉。
	口令通常对访问机器的控制台来说是必须的。 也就是说，
	您应该避免允许在控制台以外的地方使用口令，
	甚至包括使用 &man.su.1; 命令的情形。
	例如，确信您的 pty 终端在 <filename>/etc/ttys</filename>
	文件中被指定为 insecure (不安全)，这将使直接通过
	<command>telnet</command> 或 <command>rlogin</command> 登录
	<username>root</username> 会不被接受。 如果使用如
	<application>sshd</application> 这样的其他登录服务，
	也要确认直接登录 root 是关闭的。您可以通过编辑
	<filename>/etc/ssh/sshd_config</filename> 文件来做到这一点，确信
	<literal>PermitRootLogin</literal> 被设置成 <literal>NO</literal>。
	考虑到每一种访问方法 &mdash; 如FTP这样的服务，
	以免因为它们而导致安全性的损失。
	直接登录 <username>root</username> 只有通过系统控制台才被允许。</para>
      <indexterm>
        <primary><groupname>wheel</groupname></primary>
      </indexterm>

      <para>当然， 作为一个系统管理员， 您应当获得
	<username>root</username>身份， 因此， 我们开了一些后门来允许自己进入。
	但这些后门只有在经过了额外的口令确认之后才能使用。
	一种让 <username>root</username>
	可访问的方法是增加适当的用户帐户到
	<groupname>wheel</groupname> 组 (在
	<filename>/etc/group</filename> 中)。<groupname>wheel</groupname>
	组中的用户成员可以使用 <command>su</command>
	命令来成为 <username>root</username>。
	绝对不应该通过在口令项中进行设置来赋予维护人员天然的
	<groupname>wheel</groupname> 组成员身份。 维护人员应被放置在
	<groupname>staff</groupname> 组中，然后通过
	<filename>/etc/group</filename> 文件加入到 <groupname>wheel</groupname>
	组。事实上，只有那些需要以 <username>root</username> 身份进行操作的用户才需要放进
	<groupname>wheel</groupname> 组中。 当然，也可以通过
	某种其它的验证手段，例如 Kerberos，可以通过 <username>root</username>
	帐户中的 <filename>.k5login</filename> 文件来允许执行
	&man.ksu.1; 成为 <username>root</username> ，而不必把它们放进
	<groupname>wheel</groupname> 组。 这可能是一种更好的解决方案，
	因为 <groupname>wheel</groupname> 机制仍然可能导致入侵者获得
	<username>root</username> ，如果他拿到了口令文件，并能够进入职员的帐户。
	尽管有 <groupname>wheel</groupname> 比什么都没有要强一些，
	但它并不是一种绝对安全的办法。</para>

      <!-- XXX:
	This will need updating depending on the outcome of PR bin/71147.
	Personally I know what I'd like to see, which puts this in definite
	need of a rewrite, but we'll have to wait and see.  ceri@
      -->

      <para>一种间接地提高员工帐号， 乃至 <username>root</username>
	权限安全性的方法， 便是采用其他的登录访问方式，
	并使用 <quote>星号</quote>
	替代员工加密的口令。使用 &man.vipw.8; 命令，
	可以把每一个加密的口令替换成一个 <quote><literal>*</literal></quote> 符。
	这将更新 <filename>/etc/master.passwd</filename> 文件，以及
	用户名/口令数据库，以禁用口令登录。</para>

      <para>如下面的员工帐号</para>

      <programlisting>foobar:R9DT/Fa1/LV9U:1000:1000::0:0:Foo Bar:/home/foobar:/usr/local/bin/tcsh</programlisting>

      <para>应被改为：</para>

      <programlisting>foobar:*:1000:1000::0:0:Foo Bar:/home/foobar:/usr/local/bin/tcsh</programlisting>

      <para>这一更改将阻止一般的登录，因为加密的口令永远不会与
        <quote><literal>*</literal></quote> 匹配。一旦这么做之后，
        任何员工都必须使用其他的方式来完成登录，例如，使用
        &man.kerberos.1; 或者通过 &man.ssh.1; 利用 公钥/密钥对
        的方式来完成登录。当使用 Kerberos 这样的工具时，通常必须加强运行
        Kerberos 的服务器，以及桌面工作站的安全性。当使用 公钥/密钥对以
        ssh 登录时，通常必须加固用户 <emphasis>开始</emphasis>
        登录的那台机器的安全 (通常这是他们的工作站)。
        在这之上还可以增加一层安全性，即在使用 &man.ssh-keygen.1;
        生成它的时候，使用口令来保护它们。 如果能够用
        <quote>星号</quote> 替换掉所有员工的口令，
        那么，这也就保证了他们只能通过您设置的安全的方法来登录。
        这将迫使所有的员工使用安全的、经过加密的连接来完成他们的会话，
        而这将使得入侵者通过监听网络通讯， 从某些不相关的、
        不太安全的机器上窃取口令成为不可能。</para>

      <para>另一种间接的安全机制则是，
	从严格受限的机器向限制更宽松的机器上登录。 例如，
	如果您的服务器运行了所有的服务，那么，工作站应该什么都不运行。
	为了让工作站尽可能地安全，应该避免运行任何没有必要的服务，
	甚至不运行任何服务。 另外， 也应该考虑使用带口令保护功能的屏幕保护程序。
	毋庸置疑， 如果攻击者能够物理地接触您的工作站，
	那么他就有能力破坏任何安全设施，这确实是我们需要考虑的一个问题，但同样地，
	真正能够物理接触您的工作站或服务器并实施攻击的人在现实生活中并不常见，
	绝大多数攻击来自于网络， 而攻击者往往无法物理地接触服务器或工作站。</para>
      <indexterm><primary>KerberosIV</primary></indexterm>

      <para>使用类似 Kerberos 这样的工具，也为我们提供了使用一个工具来禁用某个用户，
	或修改他们的口令， 并在所有机器上立即生效的方法。 如果员工的帐号被窃取，
	能够在所有的其他机器上生效的口令变更将很有意义。如果口令分散地保存在多个机器上，
	一次修改 N 台机器上的口令很可能是一件痛苦的事情。
	此外， Kerberos 还能够提供更多的限制，除了 Kerberos 令牌有很好的过期机制之外，
	它还能够强制用户在某个特定的期限内修改口令(比如说，每月一次). </para>
    </sect2>

    <sect2>
      <title>确保以root用户权限运行的服务器和suid/sgid可执行程序的安全</title>

      <indexterm>
        <primary><command>ntalk</command></primary>
      </indexterm>
      <indexterm>
        <primary><command>comsat</command></primary>
      </indexterm>
      <indexterm>
        <primary><command>finger</command></primary>
      </indexterm>
      <indexterm>
        <primary>sandboxes</primary>
      </indexterm>
      <indexterm>
        <primary><application>sshd</application></primary>
      </indexterm>
      <indexterm>
        <primary><application>telnetd</application></primary>
      </indexterm>
      <indexterm>
        <primary><application>rshd</application></primary>
      </indexterm>
      <indexterm>
        <primary><application>rlogind</application></primary>
      </indexterm>

      <para>谨慎的管理员只运行他们需要的服务， 不多， 不少。
	要当心第三方的服务程序很可能有更多的问题。 例如， 运行旧版的
	<application>imapd</application> 或
	<application>popper</application> 无异于将
	<username>root</username> 令牌拱手送给全世界的攻击者。
	永远不要运行那些您没有仔细检查过的服务程序， 另外也要知道，
	许多服务程序并不需要以 <username>root</username> 的身份运行。
	例如， <application>ntalk</application>、
	<application>comsat</application>， 以及
	<application>finger</application> 这些服务，
	都能够以一种被称作 <firstterm>沙盒</firstterm> 的特殊用户的身份运行。
	除非您已经解决掉了许多麻烦的问题， 否则沙盒就不是完美的，
	但洋葱式安全规则仍然成立： 如果有人设法攻破了在沙盒中运行的程序，
	那么在做更多坏事之前， 他们还必须想办法攻破沙盒本身的限制。
	攻击者需要攻破的层次越多， 他们成功的可能性就越小。
	过去， 破解 root 的漏洞几乎在所有以 <username>root</username>
	身份运行的服务上都发现过， 包括那些基本的系统服务。
	如果您的机器只打算向外界提供
	<application>sshd</application> 登录， 而用户不会使用
	<application>telnetd</application> 或
	<application>rshd</application> 甚至
	<application>rlogind</application> 登录，
	就应该毫不犹豫地关闭它们！</para>
      
      <para>&os; 现在默认在沙盒中运行
	<application>ntalkd</application>,
	<application>comsat</application>, 以及
	<application>finger</application>。此外， &man.named.8; 也可以这样运行。
	<filename>/etc/defaults/rc.conf</filename> 中包括了如何如此运行
	<application>named</application> 的方法，只是这些内容被注释掉了。
	如何升级或安装系统将决定这些沙盒所使用的特殊用户是否被自动安装。
	谨慎的系统管理员将根据需要研究并实现沙盒。</para>
      <indexterm>
        <primary><application>sendmail</application></primary>
      </indexterm>

      <para>此外，还有一些服务通常并不在沙盒中运行：
	<application>sendmail</application>,
	<application>popper</application>,
	<application>imapd</application>, <application>ftpd</application>,
	以及一些其他的服务。当然，它们有一些替代品，但安装那些服务可能需要做更多额外的工作。
	可能必须以 <username>root</username> 身份运行这些程序，
	并通过其他机制来检测入侵。</para>

      <para>系统中另一个比较大的 <username>root</username> 漏洞
	是安装在其中的 suid-root 和 sgid 的可执行文件。绝大多数这类程序，
	例如 <application>rlogin</application>, 被存放于
	<filename>/bin</filename>, <filename>/sbin</filename>,
	<filename>/usr/bin</filename>, 或 <filename>/usr/sbin</filename> 中。
	尽管并没有 100% 的安全保证，但系统默认的 suid 和 sgid 可执行文件通常是相对安全的。
	当然，偶尔也会发现一些存在于这些可执行文件中的
	<username>root</username> 漏洞。1998年，<literal>Xlib</literal>
	中发现了一处 <username>root</username> 漏洞，这使得
	<application>xterm</application> (通常是做了suid的) 变得可以入侵。
	做的安全些， 总比出现问题再后悔要强。
	因此，谨慎的管理员通常会限制 suid 可执行文件，
	并保证只有员工帐号能够执行它们，或只开放给特定的用户组，甚至彻底干掉
	(<command>chmod 000</command>) 任何 suid 可执行文件，
	以至于没有人能够执行它们。没有显示设备的服务器通常不会需要
	<application>xterm</application> 可执行文件。 sgid 可执行文件通常同样地危险。
	一旦入侵者攻克了sgid-kmem，那么他就能够读取
	<filename>/dev/kmem</filename> 并进而读取经过加密的口令文件，
	从而窃取任何包含口令的帐号。另外，攻破了 <literal>kmem</literal>
	的入侵者能够监视通过 pty 传送的按键序列，即使用户使用的是安全的登录方式。
	攻破了 <groupname>tty</groupname> 组的用户则能够向几乎所有用户的
	tty 写入数据。如果用户正在运行一个终端程序，或包含了键盘模拟功能的终端仿真程序，
	那么，入侵者能够以那个用户的身份执行任何命令。</para>
    </sect2>

    <sect2 id="secure-users">
      <title>确保用户帐户的安全</title>

      <para>用户帐号的安全通常是最难保证的。虽然您可以为您的员工设置严苛的登录限制，
	并用 <quote>星号</quote> 替换掉他们的口令，但您可能无法对普通的用户这么做。
	如果有足够的决策权，那么在保证用户帐号安全的斗争中或许会处于优势，
	但如果不是这样，您能做的只是警惕地监控这些帐号的异动。
	让用户使用 ssh 或  Kerberos 可能会有更多的问题，
	因为需要更多的管理和技术支持，尽管如此，与使用加密的口令文件相比，
	这仍不失为一个好办法。</para>
    </sect2>

    <sect2>
      <title>确保口令文件的安全</title>

      <para>尽可能使用 <literal>*</literal> 替换掉口令是保证口令文件安全唯一的解决方法，
	如果能够用 ssh 或 Kerberos 的话。即使只有
	<username>root</username> 用户能够读取加密过的口令文件 (<filename>/etc/spwd.db</filename>)，
	入侵者仍然可能设法读到它的内容，
	即使他暂时还无法写入这个文件。</para>

      <para>您的安全脚本应该经常检查并报告口令文件的异动 (参见后面的 <link
	  linkend="security-integrity">检查文件完整性</link> 一节)。</para>
    </sect2>

    <sect2>
      <title>确保内核中内核设备、直接访问设备和文件系统的安全</title>

      <para>如果攻击者已经拿到了 <username>root</username> 那么他就有能力作任何事情，
	当然， 有一些事情是他们比较喜欢干的。
	例如， 绝大多数现代的内核都包括一个内建的听包设备。
	在 &os; 中，这个设备被称作
	<devicename>bpf</devicename> 。攻击者通常会尝试在攻克的系统上运行它。
	如果您不需要 <devicename>bpf</devicename> 设备提供的功能，那么，就不要把它编入内核。</para>

      <indexterm>
        <primary><command>sysctl</command></primary>
      </indexterm>
      <para>但即使已经关掉了 <devicename>bpf</devicename>
	设备，您仍然需要担心
	<filename>/dev/mem</filename> 和 <filename>/dev/kmem</filename> 。
	就事论事地说，攻击者仍然能够通过直接访问的方式写入磁盘设备。同样地，
	还有一个被称作模块加载器， &man.kldload.8; 的机制，也会包含潜在的危险。
	尝试入侵企业网络的入侵者会尝试在正在运行的内核上安装他自己的
	<devicename>bpf</devicename> 设备，或其他听包设备。为了防止这些问题，
	需要抬高内核安全级，至少调整到1。可以通过对  <varname>kern.securelevel</varname>
	执行 <command>sysctl</command> 来完成这个任务。一旦把安全级调整到1，
	对于直接访问设备的写入操作将被拒绝，而特殊的 <command>chflags</command>
	标记，如 <literal>schg</literal> ，将被强制执行。一定要在重要的启动执行文件、
	目录和脚本文件上设置 <literal>schg</literal> 标记 &mdash;
	在安全级生效之前的所有文件。这可能做得有些过火，
	并将导致在较高安全级上运行时升级系统变得困难。 此外，
	运行于较高安全级上，而没有正确设置 <literal>schg</literal>
	标记的系统仍然是存在弱点的。另一种方法是把
	<filename>/</filename> 和 <filename>/usr</filename> 以只读方式挂接。
	此外，请注意过于严苛的安全设置将使得入侵检测同样无法进行。</para>
    </sect2>

    <sect2 id="security-integrity">
      <title>检查文件完整性: 可执行文件，配置文件和其他文件</title>

      <para>当实施严格的限制时，往往会在使用的方便性上付出代价。例如，使用
	<command>chflags</command> 来把 <literal>schg</literal> 标记
	应用到 <filename>/</filename> 和
	<filename>/usr</filename> 中的绝大多数文件上可能会起到反作用，
	因为尽管它能够保护那些文件，但同样关掉了一个很好的监测机制。
	层次化安全的最后一层可能是最重要的 &mdash; 检测。
	安全的其他部分可能相对来讲意义并不那么大 (或者，更糟糕的事情是，
	那些措施会给您安全的假象)， 假如您无法检测潜在的入侵事件。
	层次化安全最重要的功能是减缓入侵者，
	而不是彻底不让他们入侵，这能够让检测起到作用，并更好地捕捉入侵行为。</para>

      <para>检测入侵的一种好办法是查找那些被修改、删除或添加的文件。
	检测文件修改的最佳方法是与某个 (通常是中央的) 受限访问的系统上的文件进行比对。
	在一台严格限制访问的系统上撰写您的安全脚本通常不能够被入侵者察觉，
	因此，这非常重要。为了最大限度地发挥这一策略的优势，通常会使用只读的 NFS，
	或者设置 ssh 钥匙对以便为其他机器提供访问。除了网络交互之外，
	NFS可能是一种很难被察觉的方法 &mdash; 它允许您监控每一台客户机上的文件系统，
	而这种监控几乎是无法察觉的。如果一台严格受限的服务器和客户机是通过交换机连接的，
	那么 NFS 将是一种非常好的方式。 不过，如果那台监控服务器和客户机之间通过集线器
	(Hub)，或经过许多层的路由来连接，则这种方式就很不安全了，
	此时，应考虑使用 ssh ，即使这可以在审计记录中查到。</para>

      <para>一旦为这个受限的机器赋予了至少读取它应监控的客户系统的权限，
	就应该为实际的监控撰写脚本。以 NFS 挂接为例，可以用类似 &man.find.1;
	和 &man.md5.1; 这样的命令为基础来完成我们所需的工作。
	最好能够每天对被控机的所有执行文件计算一遍 md5，同时，还应以更高的频率测试那些
	<filename>/etc</filename> 和 <filename>/usr/local/etc</filename>
	中的控制文件。一旦发现了不匹配的情形，监控机应立即通知系统管理员。
	好的安全脚本也应该检查在系统分区，如 <filename>/</filename> 和
	<filename>/usr</filename> 中是否有新增或删除的可执行文件，以及不适宜的 suid 。</para>

      <para>如果打算使用 ssh 来代替 NFS，那么撰写安全脚本将变得困难许多。
	本质上，需要在脚本中使用 <command>scp</command> 在客户端复制文件，
	另一方面，用于检查的执行文件 (例如 find) 也需要使用
	<command>scp</command> 传到客户端，因为
	<application>ssh</application> 客户程序很可能已经被攻陷。
	总之，在一条不够安全的链路上 ssh 可能是必须的，
	但也必须应付它所带来的难题。</para>

      <para>安全脚本还应该检查用户以及职员成员的权限设置文件：
	<filename>.rhosts</filename>、 <filename>.shosts</filename>、
	<filename>.ssh/authorized_keys</filename> 等等。 &hellip;
	这些文件可能并非通过
	<literal>MD5</literal> 来进行检查。</para>

      <para>如果您的用户磁盘空间很大， 检查这种分区上面的文件可能非常耗时。
	这种情况下， 采用标志来禁止使用 suid 可执行文件和设备在这些文件系统上出现将是一个好主意。
	您可能会想看看 <literal>nodev</literal> 和
	<literal>nosuid</literal> 这两个选项 (参见 &man.mount.8;)。
	尽管如此， 这些扫描仍然应该至少每周进行一次， 这样做的意义并不是检测有效的攻击，
	而是检查攻击企图。</para>

      <para>进程记帐 (参见 &man.accton.8;) 是一种相对成本较低的，
	可以帮助您在被入侵后评估损失的机制。
	对于找出入侵者是如何进入系统的这件事情来说，
	它会非常的有所助益，特别是当入侵者什么文件都没有修改的情况下。</para>

      <para>最后， 安全脚本应该处理日志文件， 而日志文件本身应该通过尽可能安全的方法生成
	&mdash; 远程 syslog 可能非常有用。 入侵者会试图掩盖他们的踪迹，
	而日志文件对于希望了解入侵发生时间的系统管理员来说则显得尤为重要。
	保持日志文件的永久性记录的一种方法是在串口上运行系统控制台，
	并持续不断地在一台安全的机器上收集这些信息。</para>
    </sect2>

    <sect2>
      <title>偏执</title>

      <para>带点偏执不会带来伤害。作为一种惯例，
	系统管理员在不影响使用的便利的前提下可以启用任何安全特性，此外，
	在经过深思熟虑之后，也可以增加一些
	<emphasis>确实会</emphasis> 让使用变得不那么方便的安全特性。
	更重要的是，有安全意识的管理员应该学会混合不同的安全策略 &mdash;
	如果您逐字逐句地按照这份文档来配置您的机器，
	那无异于向那些同样能得到这份文档的攻击者透露了更多的信息。</para>
    </sect2>

    <sect2>
      <title>拒绝服务攻击</title>
      <indexterm><primary>拒绝服务 (DoS)</primary></indexterm>

      <para>这一节将介绍拒绝服务攻击。 DoS 攻击通常是基于数据包的攻击，
	尽管几乎没有任何办法来阻止大量的伪造数据包耗尽网络资源，
	但通常可以通过一些手段来限制这类攻击的损害，使它们无法击垮服务器。</para>

      <orderedlist>
	<listitem>
	  <para>限制服务进程 fork.</para>
	</listitem>

	<listitem>
	  <para>限制 springboard 攻击 (ICMP 响应攻击， ping
	    广播，等等)。</para>
	</listitem>

	<listitem>
	  <para>内核路由缓存</para>
	</listitem>
      </orderedlist>

      <para>对于通过复制进程 (fork) 来进行服务的服务器的一种很常见的攻击是想办法耗尽其进程、
	文件描述符或者内存， 直到机器彻底死掉。
	<application>inetd</application>
	(参见 &man.inetd.8;) 提供了许多选项来限制这类攻击。
	需要注意的是， 尽管能够阻止一台机器彻底垮掉，
	但通常无法防止服务本身被击垮。
	请仔细阅读 <application>inetd</application> 的联机手册，
	特别是它的 <option>-c</option>、 <option>-C</option> 以及
	<option>-R</option> 这三个选项。 伪造 IP 攻击能够绕过
	<application>inetd</application> 的 <option>-C</option> 选项，
	因此， 这些选项需要配合使用。 某些独立的服务器也有类似的限制参数。</para>

      <para>例如， <application>Sendmail</application> 就提供了自己的
	<option>-OMaxDaemonChildren</option> 选项， 它通常比 sendmail 的负载限制选项更为有效，
	因为服务器负载的计算有滞后性。 您可以在启动 <application>sendmail</application> 时指定一个
	<literal>MaxDaemonChildren</literal> 参数， 把它设的足够高以便承载您所需要的负荷，
	当然， 不要高到足以让运行 <application>sendmails</application> 的机器死掉。
	此外， 以队列模式
	(<option>-ODeliveryMode=queued</option>) 并把服务程序
	(<command>sendmail -bd</command>) 和队列执行程序分别执行
	(<command>sendmail -q15m</command>) 也是一个好主意。
	如果您希望保证队列的实时性， 可以考虑使用更短的间隔， 例如
	<option>-q1m</option>， 但同时也需要指定一个合理的子进程数， 也就是通过
	<literal>MaxDaemonChildren</literal> 选项以免
	<emphasis>那个</emphasis> sendmail 造成重叠的故障。</para>

      <para><application>Syslogd</application> 可以被直接地攻击，因此，
	强烈建议只要可行，就在启动它的时候加上 <option>-s</option> 参数，
	其他情况下，则至少应该加上 <option>-a</option>。</para>

      <para>对于基于连接的服务，例如
	<application>TCP Wrapper</application> 的 reverse-identd， 都应该格外的小心，
	因为它们都可能直接遭受攻击。 一般情况下， 基于安全考虑， 不应使用 <application>TCP Wrapper</application>
	所提供的 reverse-ident 这样的功能。</para>

      <para>此外， 将内部服务保护起来， 阻止来自其他主机的访问也十分重要，
	这些工作可以通过设置边界路由器来完成。
	主要的想法， 是阻止来自您的	LAN 以外的访问， 这有助于避免
	<username>root</username> 受到攻击。
	尽可能配置排他式的防火墙， 例如，
	<quote>用防火墙阻止所有的网络流量 <emphasis>除了</emphasis> 端口 A、B、
	C、D，以及 M-Z</quote>。 通过采用这种方法， 您可以很容易地将低端口的访问阻止在外，
	而又不难配置使防火墙放过那些明确需要开放的服务， 例如
	<application>named</application> (如果您的机器准备作为域的主要解析服务器)，
	<application>ntalkd</application>，
	<application>sendmail</application>，以及其他可以从 Internet 访问的服务。
	如果您尝试以其他方式配置防火墙
	&mdash; 采用比较宽松的策略， 那么您将很有可能忘记
	<quote>关掉</quote> 一两个服务，
	或者在增加了一些服务之后忘记更新防火墙策略。
	尽管如此， 仍然可以考虑允许让数据进入编号较高的那一部分端口，
	这将保证那些需要这样特性的服务能够正常工作，
	而又不影响低端口服务的安全性。
	此外， 还应注意到 &os; 允许您来控制动态绑定的端口的范围，
	即一系列 <varname>net.inet.ip.portrange</varname> 变量，通过
	<command>sysctl</command> 来完成设置。 (<command>sysctl -a | fgrep
	portrange</command>)。 这使得您完成较复杂的防火墙策略变得易如反掌。
	例如， 您可能希望普通的高段端口的起止范围是
	4000 到 5000， 而更高范围则是 49152 到
	65535， 随后在防火墙中阻止低于 4000 的所有端口
	(当然， 除了那些特地为 Internet 访问而开设的端口)。</para>

      <indexterm><primary>ICMP_BANDLIM</primary></indexterm>

      <para>另一种常被称作 springboard 的攻击也是非常常见的 DoS 攻击
	&mdash; 它通过使服务器产生其无法处理的响应来达到目的。
	最常见的攻击就是 <emphasis>ICMP ping 广播攻击</emphasis>。
	攻击者通过伪造 ping 包， 将其源 IP 设置为希望攻击的机器的 IP。
	如果您的边界路由器没有进行禁止 ping 广播地址的设置， 则您的网络将最终陷于响应伪造的
	ping 之中， 特别是当攻击者同时使用了多个不同的网络时。
	广播攻击能够产生超过 120 兆位的瞬时流量。
	另一种常见的针对 ICMP 错误报告系统的 springboard 攻击，
	通过建立可以生成 ICMP 出错响应的包， 攻击者能够攻击服务器的网络下行资源，
	并导致其上行资源耗尽。 这种类型的攻击也可以通过耗尽 mbuf
	来使得使得被攻击的服务器崩溃，特别是当这些服务器无法足够快地完成
	ICPM 响应的时候。 可以通过为 &os; 内核配置称为
	<option>ICMP_BANDLIM</option> 的编译选项来使这类攻击变得不那么有效。
	最后一类主要的 springboard 是针对某些
	<application>inetd</application> 的内部服务， 例如
	udp echo 服务进行的。 攻击者简单地伪造一个来自服务器 A 的
	echo 口的 UDP 包， 然后将这个包发到 B 的 echo 口。
	于是， 两台服务器将不停地将包弹给对方。
	攻击者能够将两台服务器的这种服务都耗竭，
	并且通过这种方式， 只需要很少的包就可以让 LAN 超载。 
	类似的问题对
	<application>chargen</application> 口也是存在的。
	好的系统管理员应该关闭这些 inetd 的测试服务。</para>

      <para>伪造的包攻击也可以用来使内核的路由缓存过载。
	请参考 <varname>net.inet.ip.rtexpire</varname>，
	<varname>rtminexpire</varname>， 以及 <varname>rtmaxcache</varname>
	<command>sysctl</command> 参数。 伪造的包可以用随机的源 IP 攻击，
	使得内核在路由表中产生一个临时的缓存项， 它可以通过
	<command>netstat -rna | fgrep W3</command> 看到。 这些路由通常需要
	1600 秒才会过期。 如果内核发现路由表变得太大， 它会动态地降低
	<varname>rtexpire</varname> 但以
	<varname>rtminexpire</varname> 为限。 这引发了两个问题：</para>
	
      <orderedlist>
	<listitem>
	  <para>在访问量不大的服务器上， 内核对于突然袭击的反应不够快。</para>
	</listitem>

	<listitem>
	  <para><varname>rtminexpire</varname> 的值没有低到让内核在此类攻击时活下去的程度。</para>
	</listitem>
      </orderedlist>

      <para>如果您的服务器通过 T3 或更快的线路接入 Internet，
        那么通过 &man.sysctl.8; 来手动地降低
	<varname>rtexpire</varname> 和 <varname>rtminexpire</varname>
	就非常必要。 当然，绝不要把它们设置为零 (除非您想让机器崩溃)
	将这两个参数设置为 2 通常已经足以抵御这类攻击了。</para>
    </sect2>

    <sect2>
      <title>Kerberos 和 SSH 的访问问题</title>
      <indexterm><primary><command>ssh</command></primary></indexterm>
      <indexterm><primary>KerberosIV</primary></indexterm>

      <para>如果您打算使用， 那么 Kerberos 和 ssh 都有一些需要解决的问题。
	Kerberos V 是一个很棒的验证协议， 但使用了它的
	<application>telnet</application> 和
	<application>rlogin</application> 应用程序有一些 bug，
	使得它们不适合处理二进制流。
	而且， 除非使用了 <option>-x</option> 选项， 否则默认情况下
	Kerberos 并不加密会话。
	 <application>ssh</application>
	在默认时加密所有的会话内容。</para>

      <para>除了默认转发加密密钥， ssh 在所有的其他方面都做得很好。
	这意味着如果您持有供您访问系统其他部分密钥的工作站作了很好的安全防护，
	而您连到了一台不安全的机器上， 则您的密钥可能被别人获得。
	尽管实际的密钥并没有被泄漏， 但由于 ssh 会在您登录的过程中启用一个转发端口，
	如果攻击者拿到那台不安全的机器上的
	<username>root</username> 那么他将能够利用那个端口来使用您的密钥，
	从而访问您能够访问的那些机器。</para>

      <para>我们建议您在使用 ssh 时配合
	Kerberos 来完成工作人员的登录过程。
	<application>ssh</application> 在编译时可以加入 Kerberos 支持。
	在减少了潜在地暴露 ssh 密钥的机会的同时， 它还能够通过 Kerberos 来保护口令。
	ssh 密钥只有在做过安全防护的机器上执行自动操作时才应使用
	(这是 Kerberos 不适合的情形)。 此外，我们还建议您要么在
	ssh 配置中关闭密钥转发， 要么在 <filename>authorized_keys</filename> 中增加
	<literal>from=IP/DOMAIN</literal> 选项， 来限制这些密钥能够登录的来源机器。</para>
    </sect2>
  </sect1>

  <sect1 id="crypt">
    <sect1info>
      <authorgroup>
	<author>
	  <firstname>Bill</firstname>
	  <surname>Swingle</surname>
	  <contrib>部分重写、更新来自 </contrib>
	</author>
      </authorgroup>
      <!-- 21 Mar 2000 -->
    </sect1info>

    <title>DES，MD5，以及Crypt</title>
    <indexterm>
      <primary>安全</primary>
      <secondary>密码</secondary>
    </indexterm>

    <indexterm><primary>crypt</primary></indexterm>
    <indexterm><primary>DES</primary></indexterm>
    <indexterm><primary>MD5</primary></indexterm>

    <para>&unix; 系统上的每个用户都有一个与其帐户关联的口令。
      很显然， 密码只需要被这个用户和操作系统知道。
      为了保证口令的私密性， 采用了一种称为 <quote>单向散列</quote>
      的方法来处理口令， 简单地说， 很容易从口令推算出散列值，
      反之却很难。 其实， 刚才那句话可能并不十分确切：
      因为操作系统本身并不 <emphasis>真的</emphasis> 知道您的口令。
      它只知道口令 <emphasis>经过加密的形式</emphasis>。 获取口令对应
      <quote>明文</quote> 的唯一办法是采用暴力在口令可能的区间内穷举。</para>

    <para>不幸的是，当 &unix; 刚刚出现时，安全地加密口令的唯一方法基于DES，
      数据加密标准 ( the Data Encryption Standard )。
      于是这给那些非美国居民带来了问题，
      因为 DES 的源代码在当时不能被出口到美国以外的地方，
      &os; 必须找到符合美国法律，但又要与其他那些使用 DES
      的 &unix; 版本兼容的办法。</para>

    <para>解决方案是把加密函数库分割为两个，
      于是美国的用户可以安装并使用 DES 函数库，
      而国际用户则使用另外一套库提供的一种可以出口的加密算法。
      这就是 &os; 为什么使用 MD5 作为它的默认加密算法的原因。
      MD5 据信要比 DES 更安全，因此，安装 DES 更多地是出于兼容目的。</para>

    <sect2>
      <title>识别您采用的加密算法</title>

      <para>在 &os;&nbsp;4.4 之前，<filename>libcrypt.a</filename> 曾经是
	一个指向相应加密算法的符号连接。&os;&nbsp;4.4 开始，把
	<filename>libcrypt.a</filename> 变成了一个可以配置的密码验证散列库。
	现在这个库支持 DES，MD5和Blowfish散列函数。默认情况下， &os;
	使用 MD5 来加密口令。</para>

      <para>可以很容易地识别 &os; 使用哪种加密方法。
	检查 <filename>/etc/master.passwd</filename> 文件中的加密密码是一种方法。
	用 MD5 散列加密的密码通常要比用 
	DES 散列得到的长一些， 并且以
	<literal>&dollar;1&dollar;</literal> 字符开始。 以
	<literal>&dollar;2a&dollar;</literal> 开始的口令是通过
	Blowfish 散列函数加密的。 DES 密码字符没有任何可以用于鉴别的特征，
	但他们要比 MD5 短， 并且以不包括 <literal>&dollar;</literal> 在内的
	64 个可显示字符来表示，
	因此相对比较短的、没有以美元符号开头的字符串很可能是一个 DES 口令。</para>

      <para>新口令所使用的密码格式是由 <filename>/etc/login.conf</filename>
	中的 <literal>passwd_format</literal> 来控制的， 可供选择的算法包括
	<literal>des</literal>, <literal>md5</literal> 和
	<literal>blf</literal>。 请参考 &man.login.conf.5; 联机帮助以获得更进一步的详情。</para>

    </sect2>
  </sect1>

  <sect1 id="one-time-passwords">
    <title>一次性口令</title>
    <indexterm><primary>一次性口令</primary></indexterm>
    <indexterm>
      <primary>安全</primary>
      <secondary>一次性口令</secondary>
    </indexterm>

    <para>&unix; 系统上的每个用户都有一个与其帐户关联的口令。很显然，
      为了保证口令的私密性，
      使用了一种容易加密，却很难解密的被称作 <quote>单向散列</quote>
      的方法来处理口令。换言之，我们刚刚说的那句话并不十分确切：
      操作系统本身并不 <emphasis>真的</emphasis> 知道您的口令。
      它只知道口令 <emphasis>经过加密的形式</emphasis>。
      获取口令对应
      <quote>明文</quote> 的唯一办法是采用暴力在口令可能的区间内穷举。</para>

    <para>S/Key 是基于单向 hash 功能的一次性密码管理方式。
      为了考虑兼容性而使用了 MD4 散列， 而其他系统则使用了
      MD5 和 DES-MAC。 S/Key 从 1.1.5 版之后就一直是
      &os; 基本系统的一部分， 包含这一特性的操作系统也日益增多。
      S/Key 是 Bell Communications Research, Inc. 的注册商标。</para>

    <para>从 &os; 的 5.0 版开始， S/Key 被功能相同的
      OPIE (One-time Passwords In Everything) 取代了。
      OPIE 默认使用 MD5 散列。</para>

    <para>下面将介绍三种不同的口令。
      第一种是您常用的 &unix; 风格或 Kerberos 口令; 我们在后面的章节中将称其为
      <quote>&unix; 口令</quote>。 第二种是使用 S/Key 的 <command>key</command>
      程序或 OPIE 的 &man.opiekey.1; 程序生成， 并为 <command>keyinit</command>
      或 &man.opiepasswd.1; 以及登录提示所接受的一次性口令，我们称其为
      <quote>一次性口令</quote>。 最后一类口令是您输入给
      <command>key</command>/<command>opiekey</command> 程序 (有些时候是
      <command>keyinit</command>/<command>opiepasswd</command> 程序)
      用以产生一次性口令的秘密口令，我们称其为 <quote>秘密口令</quote>
      或通俗地简称为 <quote>口令</quote>。</para>

    <para>秘密口令和您的 &unix; 口令毫无关系， 尽管可以设置为相同的，
      但不推荐这么做。 S/Key 和 OPIE 秘密口令并不像旧式的
      &unix; 口令那样只能限于8位以内<footnote><para>在 &os; 中标准的登录口令最长不能超过
      128 个字符。</para></footnote>。
      您想要用多长的口令都可以。 有六、七个词的短句是很常见的选择。
      在绝大多数时候，
      S/Key 或 OPIE 系统和 &unix; 口令系统完全相互独立地工作。</para>

    <para>除了口令之外， 对于 S/Key 和 OPIE 还有两组至关重要的数据。
      其一被称作 <quote>种子</quote> 或 <quote>key</quote>， 它包括两个字符和五个数字。
      另一个被称作 <quote>迭代轮数</quote>， 这是一个 1 到 100 之间的数字。
      S/Key 通过将种子加到秘密口令后面， 并执行迭代轮数那么多次的 MD4/MD5
      散列运算来得到结果， 并将结果表示为 6 个短的英文单词。
      这 6 个英文单词就是您的一次性口令。
      验证系统 (主要是 PAM) 会记录上次使用的一次性口令，
      如果用户提供的口令的散列值与上次一致， 则可以通过身份验证。
      由于使用了单向的散列函数， 因此即使截获了上次使用的口令，
      也没有办法恢复出下次将要使用的口令；
      每次成功登录都将导致迭代轮数递减， 这样用户和登录程序将保持同步。
      每当迭代轮数减少到 1 时， 都必须重新初始化 S/Key 和 OPIE。</para>

    <para>接下来将讨论和每个系统有关的三个程序。
      <command>key</command> 和
      <command>opiekey</command> 程序能够接收带迭代计数， 种子和秘密口令，
      并生成一个一次性口令， 或一张包含连续的一组一次性口令的表格。
      <command>keyinit</command> 和 <command>opiepasswd</command>
      程序分别用于初始化 S/Key 和 OPIE， 并修改口令、
      迭代次数、种子和一次性口令。 <command>keyinfo</command>
      和 <command>opieinfo</command> 程序可以用于检查相应的验证数据文件
      (<filename>/etc/skeykeys</filename> 或
      <filename>/etc/opiekeys</filename>) 并显示执行命令的用户当前的迭代轮数和种子。</para>

    <para>我们将介绍四种不同的操作。
      在安全的连接上通过 <command>keyinit</command> 或
      <command>opiepasswd</command> 来第一次设置一次性口令，
      或修改口令及种子。
      第二类操作是在不安全的连接上使用 <command>keyinit</command>
      或 <command>opiepasswd</command> 辅以在安全连接上执行的
      <command>key</command> 或 <command>opiekey</command>
      来完成同样的工作。 第三类操作是在不安全的连接上使用
      <command>key</command>/<command>opiekey</command> 来登录。
      最后一类操作是采用 <command>key</command>
      或 <command>opiekey</command> 来生成大批的密码，
      以便抄下来或打印出来，在没有安全连接的地方使用。</para>

    <sect2>
      <title>安全连接的初始化</title>

      <para>第一次初始化 S/Key， 修改口令或种子需要在安全的连接
	(例如， 在那台机器的控制台上或者通过 <application>ssh</application>)
	登录来完成。 以自己的身份登录并执行不带参数的
	<command>keyinit</command> 命令：</para>

      <screen>&prompt.user; <userinput>keyinit</userinput>
Adding unfurl:
Reminder - Only use this method if you are directly connected.
If you are using telnet or rlogin exit with no password and use keyinit -s.
Enter secret password:
Again secret password:

ID unfurl s/key is 99 to17757
DEFY CLUB PRO NASH LACE SOFT</screen>

      <para>对于 OPIE， 则使用 <command>opiepasswd</command>：</para>

      <screen>&prompt.user; <userinput>opiepasswd -c</userinput>
[grimreaper] ~ $ opiepasswd -f -c
Adding unfurl:
Only use this method from the console; NEVER from remote. If you are using
telnet, xterm, or a dial-in, type ^C now or exit with no password.
Then run opiepasswd without the -c parameter.
Using MD5 to compute responses.
Enter new secret pass phrase:
Again new secret pass phrase:
ID unfurl OTP key is 499 to4268
MOS MALL GOAT ARM AVID COED
</screen>

      <para>在 <prompt>Enter new secret pass phrase:</prompt> 或
        <prompt>Enter secret password:</prompt> 提示之后，
	应输入一个密码或口令字。 请留意， 这并不是您用于登录的口令，
	它用于生成一次性的登录密钥。
	<quote>ID</quote> 这一行给出了所需的参数：
	您的登录名，
        迭代轮数， 以及种子。 登录系统时，
	它能够记住这些参数并呈现给您， 因此无需记忆它们。
	最后一行给出了与您的秘密口令对应的、用于登录的一个一次性口令；
	如果您立即重新登录， 则它将是您需要使用的那个口令。</para>
    </sect2>

    <sect2>
      <title>不安全连接初始化</title>

      <para>如果您需要通过一个不安全的连接来初始化，
	则应首先在安全连接上执行过一次 <command>key</command>
        或 <command>opiekey</command>； 这可以在
	&macintosh; 的桌面附件， 或是在可信的机器的 shell 上面完成。
	此外还需要指定一个迭代轮数 (100 也许是一个较好的选择)
	也可以选择一个自己的种子， 或让计算机随机生成一个。
	在不安全的连接上 (当然是连到您希望初始化的机器上)，使用 <command>keyinit
	-s</command> 命令：</para>

      <screen>&prompt.user; <userinput>keyinit -s</userinput>
Updating unfurl:
Old key: to17758
Reminder you need the 6 English words from the key command.
Enter sequence count from 1 to 9999: <userinput>100</userinput>
Enter new key [default to17759]:
s/key 100 to 17759
s/key access password:
s/key access password:<userinput>CURE MIKE BANE HIM RACY GORE</userinput>
</screen>

      <para>对于 OPIE， 则需要使用 <command>opiepasswd</command>：</para>

      <screen>&prompt.user; <userinput>opiepasswd</userinput>

Updating unfurl:
You need the response from an OTP generator.
Old secret pass phrase:
        otp-md5 498 to4268 ext
        Response: GAME GAG WELT OUT DOWN CHAT
New secret pass phrase:
        otp-md5 499 to4269
        Response: LINE PAP MILK NELL BUOY TROY

ID mark OTP key is 499 gr4269
LINE PAP MILK NELL BUOY TROY
</screen>

      <para>为了接受默认的种子 (
	<command>keyinit</command> 程序令人困惑地将其称作
	<literal>key</literal>)， 按下 <keycap>Return</keycap>。
	在输入访问口令之前， 到一个有安全连接或
	S/Key 桌面附件的机器上， 并给它同样的参数：</para>

      <screen>&prompt.user; <userinput>key 100 to17759</userinput>
Reminder - Do not use this program while logged in via telnet or rlogin.
Enter secret password: <userinput>&lt;secret password&gt;</userinput>
CURE MIKE BANE HIM RACY GORE</screen>

      <para>对于 OPIE：</para>

      <screen>&prompt.user; <userinput>opiekey 498 to4268</userinput>
Using the MD5 algorithm to compute response.
Reminder: Don't use opiekey from telnet or dial-in sessions.
Enter secret pass phrase:
GAME GAG WELT OUT DOWN CHAT
</screen>

      <para>现在回到不安全的连接， 并将生成的一次性口令粘贴到相应的应用程序中。</para>
    </sect2>

    <sect2>
      <title>生成一个一次性密码</title>

      <para>一旦初始化过 S/Key 或 OPIE， 当您登录时将看到类似这样的提示：</para>

<screen>&prompt.user; <userinput>telnet example.com</userinput>
Trying 10.0.0.1...
Connected to example.com
Escape character is '^]'.

FreeBSD/i386 (example.com) (ttypa)

login: <userinput>&lt;username&gt;</userinput>
s/key 97 fw13894
Password: </screen>

      <para>对于 OPIE 则是：</para>

<screen>&prompt.user; <userinput>telnet example.com</userinput>
Trying 10.0.0.1...
Connected to example.com
Escape character is '^]'.

FreeBSD/i386 (example.com) (ttypa)

login: <userinput>&lt;username&gt;</userinput>
otp-md5 498 gr4269 ext
Password: </screen>

      <para>另外， S/Key 和 OPIE 提示有一个很有用的特性
	(这里没有表现出来)： 如果您在口令提示处按下 <keycap>Return</keycap>(回车)
	系统将回显刚键入的口令， 您可以藉此看到自己所键入的内容。
	如果试图手工键入一个一次性密码， 这会非常有用。</para>

      <indexterm><primary>MS-DOS</primary></indexterm>
      <indexterm><primary>Windows</primary></indexterm>
      <indexterm><primary>MacOS</primary></indexterm>

      <para>此时您需要生成一个一次性密码来回答这一提示。
	这项工作必须在一个可信的系统上执行 <command>key</command> 或
        <command>opiekey</command> 来完成。  (也可以找到 DOS、
	&windows; 以及 &macos; 等操作系统上运行的版本)。
	这个程序需要将迭代轮数和种子提供给它。
	您可以从登录提示那里复制和粘贴它们。</para>

      <para>在可信的系统上：</para>

      <screen>&prompt.user; <userinput>key 97 fw13894</userinput>
Reminder - Do not use this program while logged in via telnet or rlogin.
Enter secret password:
WELD LIP ACTS ENDS ME HAAG</screen>

      <para>对于 OPIE：</para>

      <screen>&prompt.user; <userinput>opiekey 498 to4268</userinput>
Using the MD5 algorithm to compute response.
Reminder: Don't use opiekey from telnet or dial-in sessions.
Enter secret pass phrase:
GAME GAG WELT OUT DOWN CHAT</screen>

      <para>现在使用刚刚生成的一次性口令登录：</para>

      <screen>login: <userinput>&lt;username&gt;</userinput>
s/key 97 fw13894
Password: <userinput>&lt;return to enable echo&gt;</userinput>
s/key 97 fw13894
Password [echo on]: WELD LIP ACTS ENDS ME HAAG
Last login: Tue Mar 21 11:56:41 from 10.0.0.2 ... </screen>

    </sect2>

    <sect2>
      <title>产生多个一次性口令</title>

      <para>有时，会需要到不能访问可信的机器或安全连接的地方。
	这种情形下， 可以使用 <command>key</command> 和
	<command>opiekey</command> 命令来一次生成许多一次性口令。 例如：</para>

      <screen>&prompt.user; <userinput>key -n 5 30 zz99999</userinput>
Reminder - Do not use this program while logged in via telnet or rlogin.
Enter secret password: <userinput>&lt;secret password&gt;</userinput>
26: SODA RUDE LEA LIND BUDD SILT
27: JILT SPY DUTY GLOW COWL ROT
28: THEM OW COLA RUNT BONG SCOT
29: COT MASH BARR BRIM NAN FLAG
30: CAN KNEE CAST NAME FOLK BILK</screen>

      <para>对于 OPIE：</para>

      <screen>&prompt.user; <userinput>opiekey -n 5 30 zz99999</userinput>
Using the MD5 algorithm to compute response.
Reminder: Don't use opiekey from telnet or dial-in sessions.
Enter secret pass phrase: <userinput>&lt;secret password&gt;</userinput>
26: JOAN BORE FOSS DES NAY QUIT
27: LATE BIAS SLAY FOLK MUCH TRIG
28: SALT TIN ANTI LOON NEAL USE
29: RIO ODIN GO BYE FURY TIC
30: GREW JIVE SAN GIRD BOIL PHI</screen>

      <para><option>-n 5</option> 按顺序请求 5 个口令，
	<option>30</option> 则指定了最后一个迭代轮数应该是多少。
	注意这些口令将按与使用顺序相反的顺序来显示。
	如果您比较偏执， 可以手工写下这些结果；
	一般来说把它粘贴到 <command>lpr</command> 就可以了。
	注意，每一行都显示迭代轮数及其对应的一次性的密码；
	一些人建议用完一个就划掉一个。</para>
    </sect2>

    <sect2>
      <title>限制使用 &unix; 口令</title>

      <para>S/Key 可以对 &unix; 口令的使用实施基于主机名、
	用户名、 终端端口或登录会话的 IP 地址的各种限制。
	这些限制可以在配置文件 <filename>/etc/skey.access</filename> 中找到。
	&man.skey.access.5; 联机帮助提供了关于文件格式的详细资料，
	并给出了更详细的使用这一配置文件时在安全方面需要注意的事项。</para>

      <para>如果没有 <filename>/etc/skey.access</filename> 这个文件
	(在 &os; 4.X 系统上这是默认的)， 那么所有的用户都可以使用
	&unix; 口令。  然而如果它存在，
	所有的用户将被要求使用 S/Key，
	除非明确地在
	<filename>skey.access</filename> 中配置允许这样做。
	无论如何， &unix; 在控制台上总是可用的。</para>

      <para>下面是一个示例的 <filename>skey.access</filename> 配置文件，
	它展示了最常用的三类配置语句：</para>

      <programlisting>permit internet 192.168.0.0 255.255.0.0
permit user fnord
permit port ttyd0</programlisting>

      <para>第一行 (<literal>permit internet</literal>) 允许来自 IP
	源地址 (需要注意这是可能被伪造的) 与指定的掩码值进行逻辑与之后，
	与给定值匹配的用户使用 &unix; 口令。 这不应被认为是一种安全机制，
	它只是为那些使用不安全网络的获得许可的用户提供了用 S/Key
	进行身份验证的手段。</para>

      <para>第二行 (<literal>permit user</literal>) 允许指定的用户，
	在本例中是 <username>fnord</username>， 在任何时候使用
	&unix; 口令。 一般说来， 只应为无法使用
	<command>key</command> 程序， 例如那些使用哑终端，
	或无法学会如何使用它的用户启用这样的功能。</para>

      <para>第三行 (<literal>permit port</literal>) 允许通过指定终端线的用户使用
	&unix; 口令； 这可以被用于拨号用户。</para>

      <para>OPIE 可以像 S/Key 一样对 &unix; 口令的使用进行基于 IP 的登录限制。
	对应的文件是 <filename>/etc/opieaccess</filename>， 在
	在 &os; 5.0 和更高版本的系统中， 默认情况下它就已经存在了。
	请参阅 &man.opieaccess.5; 以了解关于这个文件进一步的情况，
	以及安全方面需要进行的一些考虑。</para>
	
      <para>下面是一个示范的 <filename>opieaccess</filename> 文件：</para>

      <programlisting>permit 192.168.0.0 255.255.0.0</programlisting>

      <para>这行允许指定 IP 地址的用户 (再次强调这种地址容易被伪造)
	在任何时候使用 &unix; 口令登录。</para>

      <para>如果 <filename>opieaccess</filename> 中没有匹配的规则，
	则将默认拒绝任何非 OPIE 登录。</para>

    </sect2>
  </sect1>

  <sect1 id="tcpwrappers">
    <sect1info>
      <authorgroup>
	<author>
	  <firstname>Tom</firstname>
	  <surname>Rhodes</surname>
	  <contrib>作者：</contrib>
	</author>
      </authorgroup>
    </sect1info>

    <indexterm><primary>TCP Wrappers</primary></indexterm>
      
    <title>TCP Wrappers</title>

    <para>每一个熟悉 &man.inetd.8; 都应该听说过
      <acronym>TCP</acronym> Wrappers，
      但几乎没有人对它在网络环境中的作用有全面的理解。
      几乎每个人都会安装防火墙来处理网络连接，
      然而虽然防火墙有非常广泛的用途， 它却不是万能的，
      例如它无法处理类似向连接发起者发送一些文本这样的任务。
      而 <acronym>TCP</acronym> 软件能够完成它以及更多的其他事情。
      接下来的几段中将讨论许多
      <acronym>TCP</acronym> Wrappers 提供的功能，
      并且， 还给出了一些配置实例。</para>

    <para><acronym>TCP</acronym> Wrappers 软件扩展了
      <command>inetd</command> 为受其控制的服务程序实施控制的能力。
      通过使用这种方法， 它能够提供日志支持、 返回消息给联入的连接、
      使得服务程序只接受内部连接， 等等。
      尽管防火墙也能够完成其中的某些功能，
      但这不仅增加了一层额外的保护，
      也提供了防火墙无法提供的功能。</para>

    <para>然而， 由 <acronym>TCP</acronym> Wrappers
      提供的一些额外的安全功能， 不应被视为好的防火墙的替代品。
      <acronym>TCP</acronym> Wrappers 应结合防火墙或其他安全加强设施一并使用，
      为系统多提供一层安全防护。</para>

    <para>由于这些配置是对于
      <command>inetd</command> 的扩展， 因此，
      读者应首先阅读 <link linkend="network-inetd">配置 inetd</link>
      这节。</para>

    <note>
      <para>尽管由 &man.inetd.8; 运行的程序并不是真正的
	<quote>服务程序</quote>， 但传统上也把它们称为服务程序。
	下面仍将使用这一术语。</para>
    </note>

    <sect2>
      <title>初始配置</title>

      <para>在 &os; 中使用 <acronym>TCP</acronym>
	Wrappers 的唯一要求是确保 <command>inetd</command>
	在从 <filename>rc.conf</filename> 中启动时包含了
	<option>-Ww</option> 选项； 这是默认的设置。
	当然， 还需要对
	<filename>/etc/hosts.allow</filename> 进行适当的配置， 但
	&man.syslogd.8; 在配置不当时会在系统日志中记录相关消息。</para>

      <note>
	<para>与其它的 <acronym>TCP</acronym>
	  Wrappers 实现不同， 使用 <filename>hosts.deny</filename>
	  在这里被认为是不推荐和过时的做法。
	  所有的配置选项应放到
	  <filename>/etc/hosts.allow</filename> 中。</para>
      </note>

      <para>在最简单的配置中， 服务程序的连接策略是根据
	<filename>/etc/hosts.allow</filename> 允许或阻止。
	&os; 中的默认配置是允许一切发到由 <command>inetd</command>
	所启动的服务的连接请求。 在基本配置之后将讨论更复杂的情况。</para>

      <para>基本配置的形式通常是
	<literal>服务 : 地址 : 动作</literal>。
	这里 <literal>服务</literal> 是从
	<command>inetd</command> 启动的服务程序的名字。 而
	<literal>地址</literal> 可以是任何有效的主机名、 一个
	<acronym>IP</acronym> 或由方括号 ([&nbsp;])
	括起来的 IPv6 地址。 动作字段可以使 allow 或 deny，
	分别用于允许和禁止相应的访问。
	在配置时您需要注意所有的配置都是按照第一个匹配的规则运转的，
	这表示配置文件将按照顺序查找匹配规则， 而一旦找到匹配，
	则搜索也就停止了。</para>

      <para>另外也有许多其他选项， 这些将在后面介绍。
	简单的配置行从上面这些描述之中可以很容易得出。
	例如， 允许 <acronym>POP</acronym>3 连接通过
	<filename role="package">mail/qpopper</filename> 服务，
	应把下面的行添加到
	<filename>hosts.allow</filename>：</para>

      <programlisting># This line is required for POP3 connections:
qpopper : ALL : allow</programlisting>

      <para>增加这样之后， 需要重新启动 <command>inetd</command>。
	可以通过使用 &man.kill.1; 命令来完成这项工作，
	或使用 <filename>/etc/rc.d/inetd</filename>
	的 <parameter>restart</parameter> parameter 参数。</para>
      </sect2>

      <sect2>
        <title>高级配置</title>

      <para><acronym>TCP</acronym> Wrappers 也有一些高级的配置选项；
	它们能够用来对如何处理连接实施更多的控制。
	一些时候， 返回一个说明到特定的主机或请求服务的连接可能是更好的办法。
	其他情况下， 记录日志或者发送邮件给管理员可能更为适合。
	另外， 一些服务可能只希望为本机提供。
	这些需求都可以通过使用 <literal>通配符</literal>，
	扩展字符以及外部命令来实现。
	接下来的两节将介绍这些。</para>
	
      <sect3>
	<title>外部命令</title>

	<para>假设由于发生了某种状况， 而导致连接应该被拒绝掉，
	  而将其原因发送给发起连接的人。 如何完成这样的任务呢？
	  这样的动作可以通过使用 <option>twist</option> 选项来实现。
	  当发起了连接请求时， <option>twist</option>
	  将调用一个命令或脚本。 在
	  <filename>hosts.allow</filename> 文件中已经给出了一个例子：</para>

	<programlisting># The rest of the daemons are protected.
ALL : ALL \
        : severity auth.info \
        : twist /bin/echo "You are not welcome to use %d from %h."</programlisting>

	<para>这个例子将把消息
	  <quote>You are not allowed to use <literal>daemon</literal>
	  from <literal>hostname</literal>.</quote>
	  返回给访问先前没有配置过允许访问的服务客户。
	  对于希望把消息反馈给连接发起者， 然后立即切断这样的需求来说，
	  这样的配置非常有用。
	  请注意所有反馈信息
	  <emphasis>必须</emphasis> 被引号
	  <literal>"</literal> 包围； 这一规则是没有例外的。</para>

	<warning>
	  <para>如果攻击者向服务程序发送大量的连接请求，
	    则可能发动一次成功的拒绝服务攻击。</para>
	</warning>

	<para>另一种可能是针对这种情况使用 <option>spawn</option>。
	  类似 <option>twist</option>，
	  <option>spawn</option> 也暗含拒绝连接，
	  并可以用来执行外部命令或服务。
	  与 <option>twist</option> 不同的是， <option>spawn</option>
	  不会向连接发起者发送回应。
	  考虑下面的配置：</para>

	<programlisting># We do not allow connections from example.com:
ALL : .example.com \
	: spawn (/bin/echo %a from %h attempted to access %d &gt;&gt; \
	  /var/log/connections.log) \
	: deny</programlisting>

	<para>这将拒绝来自
	  <hostid role="fqdn">*.example.com</hostid> 域的所有连接；
	  同时还将记录主机名， <acronym>IP</acronym>
	  地址， 以及对方所尝试连接的服务名字到
	  <filename>/var/log/connections.log</filename> 文件中。</para>

	<para>除了前面已经介绍过的转义字符，
	  例如 %a 之外， 还有一些其它的转义符。 参考
	  &man.hosts.access.5; 联机手册可以获得完整的列表。</para>
      </sect3>

      <sect3>
	<title>通配符选项</title>

	<para>前面的例子都使用了 <literal>ALL</literal>。
	  其它选项能够将功能扩展到更远。
	  例如， <literal>ALL</literal> 可以被用来匹配每一个服务、
	  域，或 <acronym>IP</acronym> 地址。
	  另一些可用的通配符包括
	  <literal>PARANOID</literal>， 它可以用来匹配任何来自可能被伪造的
	  <acronym>IP</acronym> 地址的主机。
	  换言之， <literal>paranoid</literal> 可以被用来定义来自
	  <acronym>IP</acronym> 与其主机名不符的客户。
	  下面的例子将给您更多的感性认识：</para>

	<programlisting># Block possibly spoofed requests to sendmail:
sendmail : PARANOID : deny</programlisting>

	<para>在这个例子中， 所有连接
	  <command>sendmail</command> 的
	  <acronym>IP</acronym> 地址与其主机名不符的主机都将被拒绝。</para>

	<caution>
	  <para>如果服务器和客户机有一方的
	    <acronym>DNS</acronym> 配置不正确，
	    使用 <literal>PARANOID</literal> 可能会严重地削弱服务。
	    在设置之前， 管理员应该谨慎地考虑。</para>
	</caution>

	<para>要了解关于通配符和他们的功能，
	  请参考 &man.hosts.access.5; 联机手册。</para>

	<para>为了使设置能够生效， 应该首先把
	  <filename>hosts.allow</filename> 的第一行配置注释掉。
	  这节的开始部分已经说明了这一点。</para>
      </sect3>
    </sect2>
  </sect1>

  <sect1 id="kerberosIV">
    <sect1info>
      <authorgroup>
	<author>
	  <firstname>Mark</firstname>
	  <surname>Murray</surname>
	  <contrib>撰写者 </contrib>
	</author>
      </authorgroup>
      <authorgroup>
	<author>
	  <firstname>Mark</firstname>
	  <surname>Dapoz</surname>
	  <contrib>初稿 </contrib>
	</author>
      </authorgroup>
    </sect1info>

    <title><application>KerberosIV</application></title>

    <para>Kerberos 是一个网络附加系统/协议， 它使得用户能够通过一个安全服务器的服务来验证身份。
      象远程登录， 远程复制，
      系统间的相互文件复制和其他完成高风险任务的服务将被变得相当安全和可控制。</para>

    <para>下面将具体介绍如何配置随 &os; 发行的
      Kerberos。 不过， 您还是应该阅读相应的联机手册以获得完整的说明。</para>

    <sect2>
      <title>安装 <application>KerberosIV</application></title>

      <indexterm><primary>MIT</primary></indexterm>
      <indexterm>
	<primary>KerberosIV</primary>
	<secondary>安装</secondary>
      </indexterm>
      <para>Kerberos 是 &os; 的一项可选组件。 安装该软件最简单的办法就是
        在使用 <application>sysinstall</application> 安装 &os; 时选择
        <literal>krb4</literal> 或
        <literal>krb5</literal>。 这样将会安装
        <quote>eBones</quote> (KerberosIV) 或 <quote>Heimdal</quote> (Kerberos5)
        的 Kerberos 实现。 采用实现的原因是它们在美国/加拿大 以外的地区开发，
        因此这些国家之外的人使用， 而不必受美国的加密代码出口管制的限制。</para>

      <para>此外， 您可以从
        <filename role="package">security/krb5</filename> 得到 Kerberos 的 MIT 实现。</para>
    </sect2>

    <sect2>
      <title>创建最初的数据库</title>

      <para>这项工作只需要在 Kerberos 服务器上完成。 首先确认没有旧的
	Kerberos 数据库存在。 您应该进入到
	<filename>/etc/kerberosIV</filename> 目录中并检查下述文件是否已经存在：</para>

      <screen>&prompt.root; <userinput>cd /etc/kerberosIV</userinput>
&prompt.root; <userinput>ls</userinput>
README		krb.conf        krb.realms</screen>

      <para>如果您发现了除此之外的其它文件 (例如 <filename>principal.*</filename>
	或 <filename>master_key</filename>) 已经存在， 请使用
	<command>kdb_destroy</command> 命令来销毁旧的数据库，
	或者， 如果 Kerberos 没有在运行，简单地删除掉那些多余的文件。</para>

      <para>现在必须编辑 <filename>krb.conf</filename> 和
	<filename>krb.realms</filename> 文件来定义您的 Kerberos 领域。
	在本例中， 这个领域将是 <literal>EXAMPLE.COM</literal> 而其服务器是
	<hostid role="fqdn">grunt.example.com</hostid>。 我们编辑或创建如下的
	<filename>krb.conf</filename> 文件：</para>

      <screen>&prompt.root; <userinput>cat krb.conf</userinput>
EXAMPLE.COM
EXAMPLE.COM grunt.example.com admin server
CS.BERKELEY.EDU okeeffe.berkeley.edu
ATHENA.MIT.EDU kerberos.mit.edu
ATHENA.MIT.EDU kerberos-1.mit.edu
ATHENA.MIT.EDU kerberos-2.mit.edu
ATHENA.MIT.EDU kerberos-3.mit.edu
LCS.MIT.EDU kerberos.lcs.mit.edu
TELECOM.MIT.EDU bitsy.mit.edu
ARC.NASA.GOV trident.arc.nasa.gov</screen>

      <para>在这个例子中， 除此之外的其它领域并不是必需的。
	把他们在这里一并展示是为了演示如何让机器了解多个领域的存在。
	简单起见， 在实际的配置中可以省略它们。</para>

      <para>第一行命名了这个系统工作的领域。
	其它行包含了领域/主机的记录。
	每行的第一项是一个领域， 其后是在这个领域中充当
	<quote>密钥分发中心</quote> 的主机名。 其后的 <literal>admin
	  server</literal> 表示该主机同时还提供管理数据库服务。进一步的详细说明请参考
	Kerberos 联机手册。</para>

      <para>现在应该添加 <hostid role="fqdn">grunt.example.com</hostid>
	到 <literal>EXAMPLE.COM</literal> 领域， 同时追加一项以便将出现在
	<literal>EXAMPLE.COM</literal> 领域中
	<hostid role="domainname">.example.com</hostid> 域的所有主机也加入进来。
	<filename>krb.realms</filename> 这个文件需要按照下面的方法修改：</para>

      <screen>&prompt.root; <userinput>cat krb.realms</userinput>
grunt.example.com EXAMPLE.COM
.example.com EXAMPLE.COM
.berkeley.edu CS.BERKELEY.EDU
.MIT.EDU ATHENA.MIT.EDU
.mit.edu ATHENA.MIT.EDU</screen>

      <para>再次强调， 其它领域并不是必需的。 在这里只是要展示如何使用多个领域。
	可以删掉它们以简化配置。</para>

      <para>第一行将 <emphasis>指定的</emphasis> 系统置于所指名字的领域内。
	这一行的其它部分则指明了特定子域内的主机应该默认属于哪个领域。</para>

      <para>接下来我们就可以创建数据库了。 只有在
	Kerberos 服务器上 (或密钥分发中心上) 才需要它。 可以通过
	<command>kdb_init</command> 命令来完成这一步：</para>

      <screen>&prompt.root; <userinput>kdb_init</userinput>
<prompt>Realm name [default  ATHENA.MIT.EDU ]:</prompt> <userinput>EXAMPLE.COM</userinput>
You will be prompted for the database Master Password.
It is important that you NOT FORGET this password.

<prompt>Enter Kerberos master key:</prompt> </screen>

      <para>现在我们应该保存密钥， 这样本机上运行的其他服务就能够了解这一变化。
	用 <command>kstash</command> 命令来完成这一步：</para>

      <screen>&prompt.root; <userinput>kstash</userinput>

<prompt>Enter Kerberos master key:</prompt>

Current Kerberos master key version is 1.

Master key entered. BEWARE!</screen>

      <para>这一操作将把主口令保存到
	<filename>/etc/kerberosIV/master_key</filename>。</para>
    </sect2>

    <sect2>
      <title>让一切运转起来</title>

      <indexterm>
	<primary>KerberosIV</primary>
	<secondary>初始配置</secondary>
      </indexterm>

      <para>有两个主要的东西需要被添加到要用 Kerberos 来确保安全的
	<emphasis>每一个</emphasis> 系统上。
	它们的名字是 <literal>kpasswd</literal> 和 <literal>rcmd</literal>。
	这些程序允许另外系统改变 Kerberos 的密码， 在不同的系统上可能有不同的名字。</para>

      <para>服务程序 <application>kpasswd</application> 和
	<application>rcmd</application> 使得其他系统能够修改 Kerberos
	口令， 以及执行类似 &man.rcp.1;,
	&man.rlogin.1; 和 &man.rsh.1; 这样的命令。</para>

      <para>我们添加下面这些记录：</para>

      <screen>&prompt.root; <userinput>kdb_edit</userinput>
Opening database...

<prompt>Enter Kerberos master key:</prompt>

Current Kerberos master key version is 1.

Master key entered.  BEWARE!
Previous or default values are in [brackets] ,
enter return to leave the same, or new value.

<prompt>Principal name:</prompt> <userinput>passwd</userinput>
<prompt>Instance:</prompt> <userinput>grunt</userinput>

&lt;Not found&gt;, <prompt>Create [y] ?</prompt> <userinput>y</userinput>

Principal: passwd, Instance: grunt, kdc_key_ver: 1
<prompt>New Password:</prompt>                    &lt;---- enter RANDOM here
Verifying password

<prompt>New Password:</prompt> &lt;---- enter RANDOM here

<prompt>Random password [y] ?</prompt> <userinput>y</userinput>

Principal's new key version = 1
<prompt>Expiration date (enter yyyy-mm-dd) [ 2000-01-01 ] ?</prompt>
<prompt>Max ticket lifetime (*5 minutes) [ 255 ] ?</prompt>
<prompt>Attributes [ 0 ] ?</prompt>
Edit O.K.
<prompt>Principal name:</prompt> <userinput>rcmd</userinput>
<prompt>Instance:</prompt> <userinput>grunt</userinput>

&lt;Not found&gt;, <prompt>Create [y] ?</prompt>

Principal: rcmd, Instance: grunt, kdc_key_ver: 1
<prompt>New Password:</prompt>		&lt;---- enter RANDOM here
Verifying password

<prompt>New Password:</prompt>           &lt;---- enter RANDOM here

<prompt>Random password [y] ?</prompt>

Principal's new key version = 1
<prompt>Expiration date (enter yyyy-mm-dd) [ 2000-01-01 ] ?</prompt>
<prompt>Max ticket lifetime (*5 minutes) [ 255 ] ?</prompt>
<prompt>Attributes [ 0 ] ?</prompt>
Edit O.K.
<prompt>Principal name:</prompt>         &lt;---- null entry here will cause an exit</screen>
    </sect2>

    <sect2>
      <title>创建服务器文件</title>

      <para>现在需要分析在每台机器上定义的服务的所有情况。
	为了做到这一点， 可以使用
	<command>ext_srvtab</command> 命令。 这将创建一个文件，
	它需要被 <emphasis>通过安全的途径</emphasis> 复制或移动到每一个
	Kerberos 客户端的
	<filename>/etc/kerberosIV</filename> 目录中。
	在每一台服务器上都必须存在这个文件，
	它对 Kerberos 的运行至关重要。</para>


      <screen>&prompt.root; <userinput>ext_srvtab grunt</userinput>
<prompt>Enter Kerberos master key:</prompt>

Current Kerberos master key version is 1.

Master key entered. BEWARE!
Generating 'grunt-new-srvtab'....</screen>

      <para>现在，这个命令只产生一个临时文件，必须被重命名为 <filename>srvtab</filename>
	以便所有的服务可以识别它。 用 &man.mv.1; 命令把它挪到原系统的这个位置：</para>

      <screen>&prompt.root; <userinput>mv grunt-new-srvtab srvtab</userinput></screen>

      <para>如果文件是针对客户系统的， 而且网络可能会不安全，
	则应把
	<filename><replaceable>client</replaceable>-new-srvtab</filename> 复制到可移动的介质上，
	并通过物理上安全的方式拿走。
	将其改名为 <filename>srvtab</filename> 并放到客户机的
	<filename>/etc/kerberosIV</filename> 目录中， 并赋予
	mode 600:</para>

      <screen>&prompt.root; <userinput>mv grumble-new-srvtab srvtab</userinput>
&prompt.root; <userinput>chmod 600 srvtab</userinput></screen>
    </sect2>

    <sect2>
      <title>复制数据库</title>

      <para>现在添加一些用户记录到数据库。 首先为用户
	<username>jane</username> 创建其对应的项。 使用
	<command>kdb_edit</command> 命令来完成此项工作：</para>

      <screen>&prompt.root; <userinput>kdb_edit</userinput>
Opening database...

<prompt>Enter Kerberos master key:</prompt>

Current Kerberos master key version is 1.

Master key entered.  BEWARE!
Previous or default values are in [brackets] ,
enter return to leave the same, or new value.

<prompt>Principal name:</prompt> <userinput>jane</userinput>
<prompt>Instance:</prompt>

&lt;Not found&gt;, <prompt>Create [y] ?</prompt> <userinput>y</userinput>

Principal: jane, Instance: , kdc_key_ver: 1
<prompt>New Password:</prompt>                &lt;---- enter a secure password here
Verifying password

<prompt>New Password:</prompt>                &lt;---- re-enter the password here
Principal's new key version = 1
<prompt>Expiration date (enter yyyy-mm-dd) [ 2000-01-01 ] ?</prompt>
<prompt>Max ticket lifetime (*5 minutes) [ 255 ] ?</prompt>
<prompt>Attributes [ 0 ] ?</prompt>
Edit O.K.
<prompt>Principal name:</prompt>		   &lt;---- null entry here will cause an exit</screen>
    </sect2>

    <sect2>
      <title>测试全部相关信息</title>

      <para>首先必须启动 Kerberos 的服务程序。 这里需要指出，
	如果您正确地修改了 <filename>/etc/rc.conf</filename> 则系统在启动时会自动完成这个工作。
	只有在
	Kerberos 服务器上才需要这么做。 Kerberos 客户程序将自动地从
	<filename>/etc/kerberosIV</filename> 目录中的文件获取所需要的信息。</para>

      <screen>&prompt.root; <userinput>kerberos &amp;</userinput>
Kerberos server starting
Sleep forever on error
Log file is /var/log/kerberos.log
Current Kerberos master key version is 1.

Master key entered. BEWARE!

Current Kerberos master key version is 1
Local realm: EXAMPLE.COM
&prompt.root; <userinput>kadmind -n &amp;</userinput>
KADM Server KADM0.0A initializing
Please do not use 'kill -9' to kill this job, use a
regular kill instead

Current Kerberos master key version is 1.

Master key entered.  BEWARE!</screen>

      <para>接下来应使用 <command>kinit</command> 命令来获取与我们刚刚创建的
	ID <username>jane</username> 对应的 ticket：</para>

      <screen>&prompt.user; <userinput>kinit jane</userinput>
MIT Project Athena (grunt.example.com)
Kerberos Initialization for "jane"
<prompt>Password:</prompt> </screen>

      <para>尝试使用 <command>klist</command> 列出句柄以了解是否真的拥有它们：</para>

      <screen>&prompt.user; <userinput>klist</userinput>
Ticket file:    /tmp/tkt245
Principal:      jane@EXAMPLE.COM

  Issued           Expires          Principal
Apr 30 11:23:22  Apr 30 19:23:22  krbtgt.EXAMPLE.COM@EXAMPLE.COM</screen>

      <para>现在可以试试看用 &man.passwd.1; 来修改口令，
	以验证 <application>kpasswd</application> 服务程序是否能够从
	Kerberos 数据库中获得需要的授权：</para>

      <screen>&prompt.user; <userinput>passwd</userinput>
realm EXAMPLE.COM
<prompt>Old password for jane:</prompt>
<prompt>New Password for jane:</prompt>
Verifying password
<prompt>New Password for jane:</prompt>
Password changed.</screen>
    </sect2>

    <sect2>
      <title>授予 <command>su</command> 特权</title>

      <para>Kerberos 使我们能够给予 <emphasis>每一个</emphasis> 需要使用
	<username>root</username> 特权的用户使用他们自己
	<emphasis>单独的</emphasis> &man.su.1; 口令。
	现在我们追加一个被授予 &man.su.1; 到 <username>root</username>
	权限的 ID。 这件事是由与 <username>root</username> 相关联的一个
	principal 实例来控制的。使用 <command>kdb_edit</command>
	可以在 Kerberos 数据库中建立一个 <literal>jane.root</literal> 条目：</para>

      <screen>&prompt.root; <userinput>kdb_edit</userinput>
Opening database...

<prompt>Enter Kerberos master key:</prompt>

Current Kerberos master key version is 1.

Master key entered.  BEWARE!
Previous or default values are in [brackets] ,
enter return to leave the same, or new value.

<prompt>Principal name:</prompt> <userinput>jane</userinput>
<prompt>Instance:</prompt> <userinput>root</userinput>

&lt;Not found&gt;, Create [y] ? y

Principal: jane, Instance: root, kdc_key_ver: 1
<prompt>New Password:</prompt>                    &lt;---- enter a SECURE password here
Verifying password

<prompt>New Password:</prompt>    	 	 &lt;---- re-enter the password here

Principal's new key version = 1
<prompt>Expiration date (enter yyyy-mm-dd) [ 2000-01-01 ] ?</prompt>
<prompt>Max ticket lifetime (*5 minutes) [ 255 ] ?</prompt> <userinput>12</userinput> &lt;--- Keep this short!
<prompt>Attributes [ 0 ] ?</prompt>
Edit O.K.
<prompt>Principal name:</prompt>		         &lt;---- null entry here will cause an exit</screen>

      <para>现在试试看获得相应的句柄， 以确认它已经正常工作了：</para>

      <screen>&prompt.root; <userinput>kinit jane.root</userinput>
MIT Project Athena (grunt.example.com)
Kerberos Initialization for "jane.root"
<prompt>Password:</prompt></screen>

      <para>接下来我们需要把用户添加到 <username>root</username>的
	  <filename>.klogin</filename> 文件里：</para>

      <screen>&prompt.root; <userinput>cat /root/.klogin</userinput>
jane.root@EXAMPLE.COM</screen>

      <para>试试看 &man.su.1;：</para>

      <screen>&prompt.user; <userinput>su</userinput>
<prompt>Password:</prompt></screen>

      <para>然后看看我们拥有哪些句柄：</para>

      <screen>&prompt.root; <userinput>klist</userinput>
Ticket file:	/tmp/tkt_root_245
Principal:      jane.root@EXAMPLE.COM

  Issued           Expires          Principal
May  2 20:43:12  May  3 04:43:12  krbtgt.EXAMPLE.COM@EXAMPLE.COM</screen>
    </sect2>

    <sect2>
      <title>使用其它命令</title>

      <para>在前文给出的例子中， 我们创建了一个称为
	<literal>jane</literal> 的用户， 以及一个 <literal>root</literal> 实例。
	此处的用户名和它的 principal 相同， 这是
	Kerberos 默认的； 一个形如 <literal>&lt;username&gt;.</literal><username>root</username>
	的
	<literal>&lt;principal&gt;.&lt;instance&gt;</literal> 将允许
	<literal>&lt;username&gt;</literal> 使用 &man.su.1; 成为
	<username>root</username>， 只要所需的那些条目在 <username>root</username>
	home 目录中的
	<filename>.klogin</filename> 中存在的话：</para>

      <screen>&prompt.root; <userinput>cat /root/.klogin</userinput>
jane.root@EXAMPLE.COM</screen>

      <para>类似地， 如果用户的 home 目录中有这样的设置：</para>

      <screen>&prompt.user; <userinput>cat ~/.klogin</userinput>
jane@EXAMPLE.COM
jack@EXAMPLE.COM</screen>

      <para>则表明在 <literal>EXAMPLE.COM</literal> 领域的经过身份验证的
	<username>jane</username> 或者
	<username>jack</username> (通过 <command>kinit</command>， 详情见前文)
	能够使用 <username>jane</username> 的身份或系统 (<hostid>grunt</hostid>)
	中的文件， 无论通过	&man.rlogin.1;, &man.rsh.1; 或是
	&man.rcp.1;。</para>

      <para>举例来说， <username>jane</username> 现在通过
	Kerberos 登入了其它系统：</para>

	    <screen>&prompt.user; <userinput>kinit</userinput>
MIT Project Athena (grunt.example.com)
<prompt>Password:</prompt>
&prompt.user; <userinput>rlogin grunt</userinput>
Last login: Mon May  1 21:14:47 from grumble
Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994
        The Regents of the University of California.   All rights reserved.

FreeBSD BUILT-19950429 (GR386) #0: Sat Apr 29 17:50:09 SAT 1995</screen>

      <para>或者， 当 <username>jack</username> 登录到 <username>jane</username>
	在同一台机器上的账号
	(<username>jane</username> 按照前面所介绍的那样配置了
	<filename>.klogin</filename> 文件， 而负责 Kerberos 的管理员， 则为
	<emphasis>jack</emphasis> 的 principal 配置了一个空的 instance)：</para>

      <screen>&prompt.user; <userinput>kinit</userinput>
&prompt.user; <userinput>rlogin grunt -l jane</userinput>
MIT Project Athena (grunt.example.com)
<prompt>Password:</prompt>
Last login: Mon May  1 21:16:55 from grumble
Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994
        The Regents of the University of California.   All rights reserved.
FreeBSD BUILT-19950429 (GR386) #0: Sat Apr 29 17:50:09 SAT 1995</screen>
    </sect2>
  </sect1>

  <sect1 id="kerberos5">
    <sect1info>
      <authorgroup>
	<author>
	  <firstname>Tillman</firstname>
	  <surname>Hodgson</surname>
	  <contrib>撰写者 </contrib>
	</author>
      </authorgroup>
      <authorgroup>
	<author>
	  <firstname>Mark</firstname>
	  <surname>Murray</surname>
	  <contrib>原文来自 </contrib>
	</author>
      </authorgroup>
    </sect1info>

    <title><application>Kerberos5</application></title>

    <para>在 &os;-5.1 之后的每一个 &os; 版本都只包含
      <application>Kerberos5</application> 支持了， 因而，
      <application>Kerberos5</application> 是它们所包含的唯一的
      Kerberos 版本， 其配置在绝大多数方面和
      <application>KerberosIV</application> 非常类似。
      下述信息只适用于 &os;-5.0 之后版本中的
      <application>Kerberos5</application>。
      希望使用
      <application>KerberosIV</application> 的用户可以安装
      <filename role="package">security/krb4</filename> port。</para>

    <para><application>Kerberos</application> 是一组附加的网络系统/协议，
      用以让用户通过一台安全服务器提供的服务来验证身份。
      包括远程登录、远程复制、在系统间安全地复制文件，
      以及其它高危险性的操作， 由于其存在而显著地提高了安全型并且更加可控。</para>

    <para><application>Kerberos</application> 可以理解为一种身份验证代理系统。
      它也被描述为一种以受信第三方为主导的身份验证系统。
      <application>Kerberos</application> 只提供一种功能
      &mdash; 在网络上安全地完成用户的身份验证。
      它并不提供授权功能 (也就是说用户能够做什么操作)
      或审计功能 (记录用户作了什么操作)。
      一旦客户和服务器都使用了
      <application>Kerberos</application> 来证明各自的身份之后，
      他们还可以加密全部的通讯以保证业务数据的私密性和完整性。</para>

    <para>因此， 强烈建议将
      <application>Kerberos</application> 同其它提供授权和审计服务的安全手段联用。</para>

    <para>接下来的说明可以用来指导如何安装 &os; 所附带的
      <application>Kerberos</application>。
      不过， 您仍然需要参考相应的联机手册以获得完整的描述。</para>

    <para>为了展示 <application>Kerberos</application>
      的安装过程， 我们约定：</para>

    <itemizedlist>
      <listitem>
	<para><acronym>DNS</acronym> 域 (<quote>zone</quote>)
	  为 example.org。</para>
      </listitem>

      <listitem>
	<para><application>Kerberos</application> 领域是
	  EXAMPLE.ORG。</para>
      </listitem>
    </itemizedlist>

    <note>
      <para>在安装
	<application>Kerberos</application> 时请使用实际的域名即使您只是想在内部网上用一用。
	这可以避免 <acronym>DNS</acronym> 问题并保证了同其它
	<application>Kerberos</application> 之间的互操作性。</para>
    </note>

    <sect2>
      <title>历史</title>
      <indexterm>
	<primary>Kerberos5</primary>
	<secondary>历史</secondary>
      </indexterm>

      <para><application>Kerberos</application> 最早由
	<acronym>MIT</acronym> 作为解决网络安全问题的一个方案提出。
	<application>Kerberos</application> 协议采用了强加密，
	因此客户能够在不安全的网络上向服务器
	(以及相反地) 验证自己的身份。</para>

      <para><application>Kerberos</application> 是网络验证协议名字，
	同时也是用以表达实现了它的程序的形容词。
	(例如 <application>Kerberos</application> telnet)。
	目前最新的协议版本是 5，在
	<acronym>RFC</acronym>&nbsp;1510 中有所描述。</para>

      <para>该协议有许多免费的实现， 这些实现涵盖了许多种不同的操作系统。
	最初研制 <application>Kerberos</application> 的麻省理工学院
	(<acronym>MIT</acronym>) 也仍然在继续开发他们的 <application>Kerberos</application>
	软件包。 在 <acronym>US</acronym> 它被作为一种加密产品使用，
	因而历史上曾经受到 <acronym>US</acronym> 出口管制。
	<acronym>MIT</acronym> <application>Kerberos</application>
	可以通过 port (<filename role="package">security/krb5</filename>)
	来安装和使用。 Heimdal
	<application>Kerberos</application> 是另一种第 5 版实现，
	并且明确地在
	<acronym>US</acronym> 之外的地区开发， 以避免出口管制
	(因此在许多非商业的类 &unix; 系统中非常常用。
	Heimdal <application>Kerberos</application> 软件包可以通过
	port
	(<filename role="package">security/heimdal</filename>) 安装，
	最新的 &os; 的最小安装也会包含它。</para>

    <para>为使尽可能多的读者从中受益， 这份说明以 &os; 附带的
	Heimdal 软件包为准。</para>

    </sect2>

    <sect2>
      <title>配置 Heimdal <acronym>KDC</acronym></title>
      <indexterm>
	<primary>Kerberos5</primary>
	<secondary>密钥分发中心</secondary>
      </indexterm>

      <para>密钥分发中心 (<acronym>KDC</acronym>) 是
	<application>Kerberos</application> 提供的集中式验证服务 &mdash; 它是签发
	<application>Kerberos</application> tickets 的那台计算机。
	<acronym>KDC</acronym> 在 <application>Kerberos</application>
	领域中的其它机器看来是 <quote>受信的</quote>，
	因此必须格外注意其安全性。</para>

    <para>需要说明 <application>Kerberos</application> 服务器只需要非常少的计算资源，
	尽管如此， 基于安全理由仍然推荐使用独占的机器来扮演 <acronym>KDC</acronym>
	的角色。</para>

    <para>要开始配置 <acronym>KDC</acronym>， 首先请确认您的
	<filename>/etc/rc.conf</filename> 文件包含了作为一个
	<acronym>KDC</acronym> 所需的设置 (您可能需要适当地调整路径以适应自己系统的情况)：</para>

    <programlisting>kerberos5_server_enable="YES"
kadmind5_server_enable="YES"
kerberos_stash="YES"</programlisting>

      <note>
	<para><option>kerberos_stash</option> 只在
	  &os; 4.X 上使用。</para>
      </note>

      <para>接下来需要修改 <application>Kerberos</application>
	的配置文件， <filename>/etc/krb5.conf</filename>：</para>

      <programlisting>[libdefaults]
    default_realm = EXAMPLE.ORG
[realms]
    EXAMPLE.ORG = {
        kdc = kerberos.example.org
        admin_server = kerberos.example.org
    }
[domain_realm]
    .example.org = EXAMPLE.ORG</programlisting>

      <para>请注意这个 <filename>/etc/krb5.conf</filename> 文件假定您的
	<acronym>KDC</acronym> 有一个完整的主机名，
	即 <hostid role="fqdn">kerberos.example.org</hostid>。
	如果您的 <acronym>KDC</acronym> 主机名与它不同，
	则应添加一条 CNAME (别名) 项到 zone 中去。</para>

      <note>
	<para>对于有正确地配置过的
	  <acronym>BIND</acronym> <acronym>DNS</acronym> 服务器的大型网络，
	  上述例子可以精简为：</para>

	<programlisting>[libdefaults]
      default_realm = EXAMPLE.ORG</programlisting>

	<para>将下面的内容加入到
	  <hostid role="fqdn">example.org</hostid> zone 数据文件中：</para>

	<programlisting>_kerberos._udp      IN  SRV     01 00 88 kerberos.example.org.
_kerberos._tcp      IN  SRV     01 00 88 kerberos.example.org.
_kpasswd._udp       IN  SRV     01 00 464 kerberos.example.org.
_kerberos-adm._tcp  IN  SRV     01 00 749 kerberos.example.org.
_kerberos           IN  TXT     EXAMPLE.ORG.</programlisting></note>

      <note>
        <para>要让客户机能够找到
          <application>Kerberos</application> 服务， 您
          <emphasis>必须</emphasis> 已经配置了一个完整的
          <filename>/etc/krb5.conf</filename> 或最小配置的
          <filename>/etc/krb5.conf</filename> <emphasis>加上</emphasis>
          正确配置的 DNS 服务器。</para>
      </note>

      <para>接下来需要创建 <application>Kerberos</application> 数据库。
	这个数据库包括了使用主密码加密的所有实体的密钥。
	您并不需要记住这个密码， 它会保存在一个文件
	(<filename>/var/heimdal/m-key</filename>) 中。
	要创建主密钥，
	需要执行 <command>kstash</command> 并输入一个口令。</para>

      <para>主密钥一旦建立， 您就可以用
	<command>kadmin</command> 程序的
	<literal>-l</literal> 参数 (表示 <quote>local</quote>) 来初始化数据库了。
	这个选项让 <command>kadmin</command> 直接地修改数据库文件而不是通过
	<command>kadmind</command> 的网络服务。 这解决了在数据库创建之前连接它的鸡生蛋的问题。
	进入 <command>kadmin</command> 提示符之后， 用
	<command>init</command> 命令来创建领域的初始数据库。</para>

      <para>最后， 仍然在 <command>kadmin</command> 中， 使用
	<command>add</command> 命令来创建第一个 principal。
	暂时使用全部的默认设置， 随后可以在任何时候使用
	<command>modify</command> 命令来修改这些设置。
	另外， 也可以用 <literal>?</literal> 命令来了解可用的选项。</para>

      <para>典型的数据库创建过程如下：</para>

      <screen>&prompt.root; <userinput>kstash</userinput>
Master key: <userinput>xxxxxxxx</userinput>
Verifying password - Master key: <userinput>xxxxxxxx</userinput>

&prompt.root; <userinput>kadmin -l</userinput>
kadmin> <userinput>init EXAMPLE.ORG</userinput>
Realm max ticket life [unlimited]:
kadmin> <userinput>add tillman</userinput>
Max ticket life [unlimited]:
Max renewable life [unlimited]:
Attributes []:
Password: <userinput>xxxxxxxx</userinput>
Verifying password - Password: <userinput>xxxxxxxx</userinput></screen>

      <para>现在是启动 <acronym>KDC</acronym> 服务的时候了。
	运行 <command>/etc/rc.d/kerberos start</command> 以及
	<command>/etc/rc.d/kadmind start</command> 来启动这些服务。
	尽管此时还没有任何正在运行的 Kerberos 服务， 但您仍然可以通过获取并列出您刚刚创建的那个
	principal (用户) 的 ticket 来验证
	<acronym>KDC</acronym> 确实在正常工作， 使用
	<acronym>KDC</acronym> 本身的功能：</para>

      <screen>&prompt.user; <userinput>k5init <replaceable>tillman</replaceable></userinput>
tillman@EXAMPLE.ORG's Password:

&prompt.user; <userinput>k5list</userinput>
Credentials cache: FILE:<filename>/tmp/krb5cc_500</filename>
	Principal: tillman@EXAMPLE.ORG

  Issued           Expires          Principal
Aug 27 15:37:58  Aug 28 01:37:58  krbtgt/EXAMPLE.ORG@EXAMPLE.ORG</screen>

      </sect2>

      <sect2>
	<title>为 <application>Kerberos</application> 启用
	  Heimdal 服务</title>

        <indexterm>
	  <primary>Kerberos5</primary>
	  <secondary>启用服务</secondary>
        </indexterm>

	<para>首先我们需要一份 <application>Kerberos</application> 配置文件
	  <filename>/etc/krb5.conf</filename> 的副本。 只需简单地用安全的方式
	  (使用类似 &man.scp.1; 的网络工具， 或通过软盘) 复制
	  <acronym>KDC</acronym> 上的版本， 并覆盖掉客户机上的对应文件就可以了。</para>

	<para>接下来需要一个 <filename>/etc/krb5.keytab</filename> 文件。
	  这是提供
	  <application>Kerberos</application> 服务的服务器和工作站的一个主要区别
	  &mdash; 服务器必须有
	  <filename>keytab</filename> 文件。 这个文件包括了服务器的主机密钥，
	  这使得
	  <acronym>KDC</acronym> 得以验证它们的身份。
	  此文件必须以安全的方式传到服务器上，
	  因为如果密钥被公之于众， 则安全也就毁于一旦。
	  也就是说， 通过明文的通道， 例如 <acronym>FTP</acronym> 是非常糟糕的想法。</para>

	<para>一般来说， 您会希望使用 <command>kadmin</command> 程序来把
	  <filename>keytab</filename> 传到服务器上。
	  由于也需要使用 <command>kadmin</command> 来为主机建立 principal
	  (<acronym>KDC</acronym> 一端的
	  <filename>krb5.keytab</filename>)， 因此这并不复杂。</para>

	<para>注意您必须已经获得了一个 ticket 而且这个 ticket 必须许可使用
	  <filename>kadmind.acl</filename> 中的 <command>kadmin</command>
	  接口。 请参考 Heimdal info 中的 <quote>Remote administration(远程管理)</quote>
	  一节 (<command>info heimdal</command>) 以了解如何设计访问控制表。
	  如果不希望启用远程的
	  <command>kadmin</command> 操作， 则可以简单地采用安全的方式连接
	  <acronym>KDC</acronym> (通过本机控制台，
	  &man.ssh.1; 或 <application>Kerberos</application>
	  &man.telnet.1;) 并使用 <command>kadmin -l</command> 在本地执行管理操作。</para>

	<para>安装了 <filename>/etc/krb5.conf</filename> 文件之后，
	  您就可以使用 <application>Kerberos</application> 上的
	  <command>kadmin</command> 了。
	  <command>add --random-key</command> 命令可以用于添加主机 principal，
	  而 <command>ext</command> 命令则允许导出服务器的主机 principal 到它的
	  keytab 中。 例如：</para>

	<screen>&prompt.root; <userinput>kadmin</userinput>
kadmin><userinput> add --random-key host/myserver.example.org</userinput>
Max ticket life [unlimited]:
Max renewable life [unlimited]:
Attributes []:
kadmin><userinput> ext host/myserver.example.org</userinput>
kadmin><userinput> exit</userinput></screen>

	<para>注意 <command>ext</command> 命令 (这是
	  <quote>extract</quote> 的简写) 默认会把导出的密钥放到
	  <filename>/etc/krb5.keytab</filename> 中。</para>

	<para>如果您由于没有在 <acronym>KDC</acronym> 上运行
	  <command>kadmind</command> (例如基于安全理由) 因而无法远程地使用
	  <command>kadmin</command> 您可以直接在 <acronym>KDC</acronym>
	  上添加主机 principal
	  (<username>host/myserver.EXAMPLE.ORG</username>) 随后将其导出到一个临时文件中
	  (以免覆盖 <acronym>KDC</acronym> 上的 <filename>/etc/krb5.keytab</filename>)，
	  方法是使用下面的命令：</para>

	<screen>&prompt.root; <userinput>kadmin</userinput>
kadmin><userinput> ext --keytab=/tmp/example.keytab host/myserver.example.org</userinput>
kadmin><userinput> exit</userinput></screen>

	<para>随后需要把 keytab 复制到服务器上
	  (例如使用 <command>scp</command> 或软盘)。
	  一定要指定一个不同于默认的 keytab 名字以免覆盖
	  <acronym>KDC</acronym> 上的 keytab。</para>

	<para>到现在您的服务器已经可以同
	  <acronym>KDC</acronym> 通讯了 (因为已经配置了 <filename>krb5.conf</filename>
	  文件)， 而且它还能够证明自己的身份 (由于配置了
	  <filename>krb5.keytab</filename> 文件)。 现在可以启用一些
	  <application>Kerberos</application> 服务。
	  在这个例子中， 我们将在 <filename>/etc/inetd.conf</filename>
	  中添加下面的行来启用 <command>telnet</command>
	  服务， 随后用 <command>/etc/rc.d/inetd restart</command> 重启
	  &man.inetd.8; 服务来使设置生效：</para>

	<programlisting>telnet    stream  tcp     nowait  root    /usr/libexec/telnetd  telnetd -a user</programlisting>

	<para>关键的部分是 <command>-a</command>
	  (表示验证) 类型设置为用户 (user)。 请参考
	  &man.telnetd.8; 联机手册以了解细节。</para>

      </sect2>

      <sect2>
	<title>使用 Heimdal 来启用客户端 <application>Kerberos</application></title>

	<indexterm>
	  <primary>Kerberos5</primary>
	  <secondary>客户端配置</secondary>
	</indexterm>

	<para>设置客户机是非常简单的。 在正确配置了
	  <application>Kerberos</application> 的网络中，
	  只需要将位于 <filename>/etc/krb5.conf</filename> 的配置文件进行一下设置就可以了。
	  这一步骤可以简单地通过安全的方式将文件从
	  <acronym>KDC</acronym> 复制到客户机上来完成。</para>

	<para>尝试在客户机上执行
	  <command>kinit</command>、 <command>klist</command>， 以及
	  <command>kdestroy</command> 来测试获取、 显示并删除
	  刚刚为 principal 建立的 ticket 是否能够正常进行， 如果能，
	  则用其它的 <application>Kerberos</application> 应用程序来连接启用了
	  <application>Kerberos</application> 的服务。 如果应用程序不能正常工作而获取
	  ticket 正常， 则通常是服务本身， 而非客户机或 <acronym>KDC</acronym>
	  有问题。</para>

	<para>在测试类似 <command>telnet</command> 的应用程序时，
	  应考虑使用抓包程序 (例如 &man.tcpdump.1;)
	  来确认您的口令没有以明文方式传输。
	  尝试使用 <command>telnet</command> 的 <literal>-x</literal>
	  参数， 它将加密整个数据流 (类似
	  <command>ssh</command>)。</para>

	<para>核心的 <application>Kerberos</application> 客户端应用
	  (按照传统命名， 包括了 <command>kinit</command>、
	  <command>klist</command>、 <command>kdestroy</command>， 以及
	  <command>kpasswd</command>) 已经随
	  基本的 &os; 安装到了系统上。 请注意 5.0 之前的 &os; 版本将它们改名为
	  <command>k5init</command>、
	  <command>k5list</command>、 <command>k5destroy</command>、
	  <command>k5passwd</command>， 以及 <command>k5stash</command>
	  (尽管这些命令通常只会用到一次)。</para>

	<para>许多非核心的 <application>Kerberos</application> 客户应用程序也是默认安装的。
	  在 Hemidal 的 <quote>最小</quote> 安装理念下，
	  <command>telnet</command> 是唯一一个采用了
	  <application>Kerberos</application> 的服务。</para>

	<para>Heimdal port 则提供了一些默认不安装的客户应用程序， 例如启用了
	  <application>Kerberos</application> 版本的
	  <command>ftp</command>、 <command>rsh</command>、
	  <command>rcp</command>、 <command>rlogin</command> 以及一些更不常用的程序。
	  <acronym>MIT</acronym> port 也包括了一整套 <application>Kerberos</application>
	  客户应用程序。</para>

      </sect2>

      <sect2>
	<title>用户配置文件： <filename>.k5login</filename> 和 <filename>.k5users</filename></title>

	<indexterm>
	  <primary><filename>.k5login</filename></primary>
	</indexterm>

	<indexterm>
	  <primary><filename>.k5users</filename></primary>
	</indexterm>

	<para>在某个领域中的用户往往都有自己的
	  <application>Kerberos</application> principal (例如
	  <username>tillman@EXAMPLE.ORG</username>) 并映射到本机用户帐户
	  (例如本机上名为 <username>tillman</username> 的帐户)。
	  客户端应用程序， 如
	  <command>telnet</command> 通常并不需要用户名或 principal。</para>

	<para>不过, 有时您可能会需要赋予某些没有匹配 <application>Kerberos</application> principal
	  的人使用本地用户帐户的权限。 例如
	  <username>tillman@EXAMPLE.ORG</username> 可能需要访问本地的
	  <username>webdevelopers</username> 用户帐号。 其它
	  principal 可能也会需要访问这个本地帐号。</para>

	<para>用户 home 目录中的 <filename>.k5login</filename> 和
	  <filename>.k5users</filename> 这两个文件可以配合
	  <filename>.hosts</filename> 和 <filename>.rhosts</filename>
	  来有效地解决这个问题。 例如， 如果
	  <filename>.k5login</filename> 中有如下内容：</para>

	<screen>tillman@example.org
jdoe@example.org</screen>

	<para>并放到了本地用户
	  <username>webdevelopers</username> 的 home 目录中， 则列出的两个 principals
	  都可以使用那个帐号， 而无须共享口令。</para>

	<para>建议您在开始实施之前首先阅读这些命令的联机帮助。
	  特别地， <command>ksu</command> 的联机手册包括了
	  <filename>.k5users</filename> 的相关内容。</para>

      </sect2>

      <sect2>
	<title><application>Kerberos</application> 提示、技巧和故障排除</title>

	<indexterm>
	  <primary>Kerberos5</primary>
	  <secondary>故障排除</secondary>
	</indexterm>

	<itemizedlist>
	  <listitem>
	    <para>当使用 Heimdal 或 <acronym>MIT</acronym>
	      <application>Kerberos</application> ports 时， 需要确认
	      <envar>PATH</envar> 环境变量把 <application>Kerberos</application>
	      客户应用列在系统自带的版本之前。</para>
	  </listitem>

	  <listitem>
	    <para>同一领域内的所有计算机的时间设置是否同步？
	      如果不是的话， 则身份验证可能会失败。
	      <xref linkend="network-ntp"> 描述了如何使用
	      <acronym>NTP</acronym> 来同步时钟。</para>
	  </listitem>

	  <listitem>
	    <para><acronym>MIT</acronym> 和 Heimdal 能够很好地互操作。
	      一个例外是 <command>kadmin</command>， 因为这个协议没有被标准化。</para>
	  </listitem>

	  <listitem>
	    <para>如果您改变了主机名， 您还需要修改您的
	      <username>host/</username> principal 并更新 keytab。
	      这一规律也适用于类似 Apache 的 <filename role="package">www/mod_auth_kerb</filename>
	      所使用的 <username>www/</username> principal 这样的特殊
	      keytab 项。</para>
	  </listitem>

	  <listitem>
	    <para>您的领域中的每一台主机必须在 <acronym>DNS</acronym>
	      (或至少在 <filename>/etc/hosts</filename> 中) 可以解析
	      (同时包括正向和反向)。
	      CNAME 能够正常使用，
	      但必须有正确的对应 A 和 PTR 记录。
	      此时给出的错误信息可能很让人困惑：
	      <errorname>Kerberos5 refuses authentication because Read req
	      failed: Key table entry not found</errorname>。</para>
	  </listitem>

	  <listitem>
	    <para>某些作为客户使用您的 <acronym>KDC</acronym> 的操作系统可能没有将
	      <command>ksu</command> 设置为 setuid
	      <username>root</username> 的权限。 这意味着
	      <command>ksu</command> 将不能够正常工作，
	      从安全角度说这是一个不错的主意，
	      但可能令人烦恼。
	      这类问题并不是
	      <acronym>KDC</acronym> 的错误。</para>
	  </listitem>

	  <listitem>
	    <para>使用 <acronym>MIT</acronym>
	      <application>Kerberos</application> 时， 如果希望允许一个
	      principal 拥有超过默认的十小时有效期的 ticket 则必须使用
	      <command>kadmin</command> 中的 <command>modify_principal</command>
	      来修改 principal 本身以及 <username>krbtgt</username>
	      的 maxlife(最大有效期)。
	      此后， principal 可以使用 <command>kinit</command> 的
	      <literal>-l</literal> 参数来请求一个有更长有效期的 ticket。</para>
	  </listitem>

	  <listitem>
	    <note><para>如果在 <acronym>KDC</acronym> 上运行了听包程序，
	      并在工作站上执行 <command>kinit</command>，
	      您可能会注意到 <acronym>TGT</acronym> 是在
	      <command>kinit</command> 一开始执行的时候就发出了的 &mdash;
	      甚至在您输入口令之前！ 关于这个现象的解释是
	      <application>Kerberos</application> 服务器可以无限制地收发
	      <acronym>TGT</acronym> (Ticket Granting
	      Ticket) 给任何未经授权的请求； 但是， 每一个
	      <acronym>TGT</acronym> 都是使用用户的口令派生出来的密钥进行加密的。
	      因此， 当用户输入口令时它并不会发送给 <acronym>KDC</acronym>，
	      而是直接用于解密 <command>kinit</command> 所拿到的 <acronym>TGT</acronym>。
	      如果解密过程得到了一个包含合法的时间戳的有效 ticket，
	      则说明用户的 <application>Kerberos</application> 凭据有效。
	      这些凭据包含了一个会话密钥用以在随后建立
	      <application>Kerberos</application> 服务器的加密通讯，
	      传递由服务器自己的私钥加密的实际的 ticket-granting ticket。
	      这个第二层加密对于用户来说是看不到的， 但它使得
	      <application>Kerberos</application> 服务器能够验证每一个
	      <acronym>TGT</acronym> 的真实性。</para></note>
	  </listitem>

	  <listitem>
	    <para>如果需要有效期更长的 ticket (例如一周)
	      而且您使用 <application>OpenSSH</application>
	      连接保存您的 ticket 的机器，
	      请确认 <filename>sshd_config</filename> 中的
	      <application>Kerberos</application>
	      <option>TicketCleanup</option> 被设置为 <literal>no</literal>
	      否则在注销时会自动删除所有的 ticket。</para>
	  </listitem>

	  <listitem>
	    <para>切记主机的 principals 的 ticket 有效期一定要比用户的长。
	      如果您的用户 principal 的有效期是一周，
	      而所连接的主机的有效期是九个小时，
	      则缓存的主机 principal 将先行过期，
	      结果是 ticket 缓存无法正常工作。</para>
	  </listitem>

	  <listitem>
	    <para>当配置 <filename>krb5.dict</filename> 文件来防止使用特定的简单口令
	    (<command>kadmind</command> 的联机手册中简要介绍了它)，
	    请切记只有指定了口令策略的 principals 才会使用它们。
	    <filename>krb5.dict</filename> 文件的格式很简单：
	    每个串占一行。 创建一个到 <filename>/usr/share/dict/words</filename>
	    的符号连接会很有用。</para>
	  </listitem>
        </itemizedlist>

      </sect2>

      <sect2>
	<title>与 <acronym>MIT</acronym> port 的区别</title>

	<para><acronym>MIT</acronym> 和
	  Heimdal 主要的区别在于 <command>kadmin</command>
	  程序使用不同 (尽管等价) 的命令和协议。 如果您的
	  <acronym>KDC</acronym> 是 <acronym>MIT</acronym> 的，
	  则其影响是不能使用 Heimdal 的 <command>kadmin</command>
	  程序来远程管理 <acronym>KDC</acronym> 
	  (或相反)。</para>

	<para>完成同样工作的命令可能会有些许的不同。 推荐按照
	  <acronym>MIT</acronym>
	  <application>Kerberos</application> 的网站
	  (<ulink url="http://web.mit.edu/Kerberos/www/"></ulink>)
	  上的说明来操作。 请小心关于路径的问题，
	  <acronym>MIT</acronym> port 会默认安装到
	  <filename>/usr/local/</filename>， 您因此可能会执行
	  <quote>普通的</quote> 系统应用程序而非
	  <acronym>MIT</acronym>, 如果您的 <envar>PATH</envar> 环境变量把
	  把系统目录放在前面的话。</para>

	<note><para>如果使用 &os; 提供的 <acronym>MIT</acronym>
	  <filename role="package">security/krb5</filename> port，
	  一定要仔细阅读 port 所安装的
	  <filename>/usr/local/share/doc/krb5/README.FreeBSD</filename>，
	  如果您想知道为什么通过
	  <command>telnetd</command> 和 <command>klogind</command>
	  登录时会出现一些诡异的现象的话。 最重要地，
	  <quote>incorrect permissions on cache file(缓存文件权限不正确)</quote>
	  行为需要使用 <command>login.krb5</command> 来进行验证，
	  才能够正确地修改转发凭据的属主。</para></note>

      </sect2>

      <sect2>
	<title>缓解 <application>Kerberos</application> 的限制</title>

	<indexterm>
	  <primary>Kerberos5</primary>
	  <secondary>限制和不足</secondary>
	</indexterm>

	<sect3>
	 <title><application>Kerberos</application> 是一种 all-or-nothing 方式</title>

	  <para>在网络上启用的每个服务都必须进行修改以便让其能够配合
	    <application>Kerberos</application> 工作
	    (否则就只能使用其它方法来保护它们不受网络攻击的侵害)，
	    如果不是这样， 则用户的凭据就有可能被窃取并再次使用。
	    一个例子是对所有的远程 shell (例如通过
	    <command>rsh</command> 和 <command>telnet</command>)
	    启用了
	    <application>Kerberos</application>
	    但没有将使用明文验证的 <acronym>POP3</acronym> 邮件服务器 Kerberos化。</para>

	</sect3>

	<sect3>
	  <title><application>Kerberos</application> 是为单用户工作站设计的</title>

	  <para>在多用户环境中
	    <application>Kerberos</application> 的安全性会被削弱。
	    这是因为它把 ticket 保存到
	    <filename>/tmp</filename> 目录中， 而这个目录可以被任何用户读取。
	    如果有用户与其它人同时共享一台计算机 (也就是 multi-user)，
	    则这个用户的 ticket 就可能被其它用户窃取 (复制)。</para>

	  <para>可以通过使用 <literal>-c</literal> 文件名 这样的命令行选项，
	    或者(推荐的)改变 <envar>KRB5CCNAME</envar> 环境变量来避免这个问题，
	    但很少有人这么做。原则上， 将 ticket 保存到用户的 home
	    目录并简单地设置权限就能够缓解这个问题。</para>

	</sect3>

	<sect3>
	  <title>KDC 会成为单点崩溃故障点</title>

	  <para>根据设计， <acronym>KDC</acronym> 必须是安全的，
	    因为主密码数据库保存在它上面。 决不应该在
	    <acronym>KDC</acronym>上面运行其它服务，
	    而且还应确保它的物理安全。
	    由于 <application>Kerberos</application>
	    使用同一个密钥 (传说中的那个
	    <quote>主</quote> 密钥) 来加密所有的密码， 而将这个文件保存在
	    <acronym>KDC</acronym>， 因此其安全尤为重要</para>

	  <para>不过， 主密钥的泄露并没有想象中的那么可怕。
	    主密钥只用来加密 <application>Kerberos</application>
	    数据库以及产生随机数发生器的种子。
	    只要 <acronym>KDC</acronym> 是安全的，
	    即使攻击者拿到了主密钥也做不了什么。</para>

	  <para>另外， 如果 <acronym>KDC</acronym> 不可用
	    (例如由于拒绝服务攻击或网络故障)
	    则网络服务将由于验证服务无法进行而不能使用，
	    从而导致更大范围的拒绝服务攻击。
	    通过部署多个 <acronym>KDC</acronym> (一个主服务器，
	    配合一个或多个从服务器) 并采用经过仔细设计和实现的备用验证方式可以避免这种问题
	    (<acronym>PAM</acronym> 是一个不错的选择)。</para>

	</sect3>

	<sect3>
	  <title><application>Kerberos</application> 的不足</title>

	  <para><application>Kerberos</application> 允许用户、主机和服务之间进行相互认证。
	    但它并没有提供机制来向用户、主机或服务验证 <acronym>KDC</acronym>。
	    这意味着种过木马的程序，例如
	    <command>kinit</command> 有可能记录用户所有的用户名和密码。
	    尽管如此， 可以用类似
	    <filename role="package">security/tripwire</filename>
	    这样的文件系统完整性检查工具来避免此类情况的发生。</para>

	</sect3>
      </sect2>

      <sect2>
	<title>相关资源和其它资料</title>

	<indexterm>
	  <primary>Kerberos5</primary>
	  <secondary>外部资源</secondary>
	</indexterm>

	<itemizedlist>
	  <listitem>
	  <para><ulink
	    url="http://www.faqs.org/faqs/Kerberos-faq/general/preamble.html">
	    The <application>Kerberos</application> FAQ</ulink></para>
	</listitem>

	<listitem>
	  <para><ulink url="http://web.mit.edu/Kerberos/www/dialogue.html">Designing
	    an Authentication System: a Dialog in Four Scenes</ulink></para>
	</listitem>

	<listitem>
	  <para><ulink url="http://www.ietf.org/rfc/rfc1510.txt?number=1510">RFC 1510,
	    The <application>Kerberos</application> Network Authentication Service
	    (V5)</ulink></para>
	</listitem>

	<listitem>
	  <para><ulink url="http://web.mit.edu/Kerberos/www/"><acronym>MIT</acronym>
	    <application>Kerberos</application> home page</ulink></para>
	</listitem>

	<listitem>
	<para><ulink url="http://www.pdc.kth.se/heimdal/">Heimdal
	  <application>Kerberos</application> home page</ulink></para>
	</listitem>

	</itemizedlist>
    </sect2>
  </sect1>

  <sect1 id="openssl">
    <sect1info>
      <authorgroup>
	<author>
	  <firstname>Tom</firstname>
	  <surname>Rhodes</surname>
	  <contrib>作者 </contrib>
	</author>
      </authorgroup>
    </sect1info>
    <title>OpenSSL</title>
    <indexterm>
      <primary>安全</primary>
      <secondary>OpenSSL</secondary>
    </indexterm>

    <para>许多用户可能并没有注意到 &os; 所附带的
      <application>OpenSSL</application> 工具包的功能。
      <application>OpenSSL</application> 提供了建立在普通的通讯层基础上的加密传输层；
      这些功能为许多网络应用和服务程序所广泛使用。</para>

    <para>对 <application>OpenSSL</application> 的一些常见用法包括加密邮件客户的身份验证过程，
      基于 Web 的交易如信用卡等等。 许多 ports 如
      <filename role="package">www/apache13-ssl</filename>， 以及
      <filename role="package">mail/sylpheed-claws</filename>
      等等都提供了编译进
      <application>OpenSSL</application> 支持的方法。</para>

    <note>
      <para>绝大多数情况下 Ports Collection 会试图使用
	<filename role="package">security/openssl</filename>
	除非明确地将 <makevar>WITH_OPENSSL_BASE</makevar> make
	变量设置为 <quote>yes</quote>。</para>
    </note>

    <para>&os; 中附带的 <application>OpenSSL</application> 版本能够支持
      安全套接字层 v2/v3 (SSLv2/SSLv3) 和 安全传输层
      v1 (TLSv1) 三种网络协议， 并可作为通用的密码学函数库使用。</para>

    <note>
      <para>尽管 <application>OpenSSL</application> 支持
	<acronym>IDEA</acronym> 算法， 但由于美国专利，
	它在默认情况下是不编译的。 如果想使用它，
	请查阅相应的授权， 如果认为授权可以接受， 则可以在
	<filename>make.conf</filename> 中设置
	<makevar>MAKE_IDEA</makevar>。</para>
    </note>

    <para>为应用软件提供证书是
      <application>OpenSSL</application> 最为常用的功能之一。
      证书是一种能够确保公司或个人有效身份不被伪造的凭据。
      如果证书没有被众多 <quote>权威发证机构</quote>，
      或 <acronym>CA</acronym> 中的某一个确认，
      则会产生一个警告。 权威发证机构通常是一家公司，
      例如 <ulink url="http://www.verisign.com">VeriSign</ulink>，
      它能够通过签署来证明个人或公司证书的有效性。
      这个过程是需要付费的， 当然， 这不是使用证书的必要条件；
      然而， 这样做会让那些比较偏执的用户感到轻松。</para>

    <sect2>
      <title>生成证书</title>

      <indexterm>
	<primary>OpenSSL</primary>
	<secondary>生成证书</secondary>
      </indexterm>

      <para>为了生成证书， 需要使用下面的命令：</para>

      <screen>&prompt.root; <userinput>openssl req -new -nodes -out req.pem -keyout cert.pem</userinput>
Generating a 1024 bit RSA private key
................++++++
.......................................++++++
writing new private key to 'cert.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:<userinput><replaceable>US</replaceable></userinput>
State or Province Name (full name) [Some-State]:<userinput><replaceable>PA</replaceable></userinput>
Locality Name (eg, city) []:<userinput><replaceable>Pittsburgh</replaceable></userinput>
Organization Name (eg, company) [Internet Widgits Pty Ltd]:<userinput><replaceable>My Company</replaceable></userinput>
Organizational Unit Name (eg, section) []:<userinput><replaceable>Systems Administrator</replaceable></userinput>
Common Name (eg, YOUR name) []:<userinput><replaceable>localhost.example.org</replaceable></userinput>
Email Address []:<userinput><replaceable>trhodes@FreeBSD.org</replaceable></userinput>

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:<userinput><replaceable>SOME PASSWORD</replaceable></userinput>
An optional company name []:<userinput><replaceable>Another Name</replaceable></userinput></screen>

      <para>请注意， 在
	<quote>Common Name</quote> 提示后面我们输入的是一个域名。
	这个提示要求输入服务器的名字，
	这个名字今后将用于完成验证过程；
	如果在这里输入域名以外的内容， 那么证书也就失去其意义了。
	您还可以指定一些其他的选项， 比如证书的有效期，
	以及使用的加密算法等等。 这些选项的完整列表，
	可以在 &man.openssl.1; 联机手册中找到。</para>

      <para>上述命令执行完之后应该会在当前目录生成一个 <filename>cert.pem</filename>
	文件。 这就是刚刚生成的证书， 您可以把它发给任意一家
	<acronym>CA</acronym> 进行签署。</para>

      <para>如果不需要来自 <acronym>CA</acronym> 的签名，
	也可以创建自行签名的证书。 首先，
	需要生成 <acronym>RSA</acronym> 密钥：</para>

      <screen>&prompt.root; <userinput>openssl dsaparam -rand -genkey -out
<filename>myRSA.key</filename> 1024</userinput></screen>
	
	<para>接下来， 生成 <acronym>CA</acronym> 密钥：</para>

      <screen>&prompt.root; <userinput>openssl gendsa -des3 -out \
<filename>myca.key</filename> <filename>myRSA.key</filename></userinput></screen>

      <para>然后用这个密钥来创建证书：</para>

      <screen>&prompt.root; <userinput>openssl req -new -x509 -days 365 -key \
<filename>myca.key</filename> -out <filename>new.crt</filename></userinput></screen>

      <para>上述步骤将在当前目录中生成两个新文件：
	一个是权威发证机构的签名文件， <filename>myca.key</filename>；
	另一个是证书本身， <filename>new.crt</filename>。
	这些文件应该放到同一个目录中， 一般而言， 推荐放到
	<filename class="directory">/etc</filename>，
	并且只允许 <username>root</username> 读取。
	建议把权限设置为 0700， 这可以通过 <command>chmod</command>
	工具来完成。</para>
    </sect2>

    <sect2>
      <title>使用证书的一个例子</title>

      <para>那么有了这些文件可以做些什么呢？ 一个比较典型的用法是用来加密
	<application>Sendmail</application> <acronym>MTA</acronym>
	的通讯连接。 这可以解决用户通过本地 <acronym>MTA</acronym>
	发送邮件时使用明文进行身份验证的问题。</para>

      <note>
	<para>这个用法可能并不完美， 因为某些
	  <acronym>MUA</acronym> 会由于没有在本地安装证书而向用户发出警告。
	  请参考那些软件的说明了解关于安装证书的信息。</para>
      </note>

      <para>下面的设置应添加到本地的
	<filename>.mc</filename> 文件</para>

      <programlisting>dnl SSL Options
define(`confCACERT_PATH',`/etc/certs')dnl
define(`confCACERT',`/etc/certs/new.crt')dnl
define(`confSERVER_CERT',`/etc/certs/new.crt')dnl
define(`confSERVER_KEY',`/etc/certs/myca.key')dnl
define(`confTLS_SRV_OPTIONS', `V')dnl</programlisting>

      <para>这里， <filename class="directory">/etc/certs/</filename>
	是准备用来在本地保存证书和密钥的位置。 最后，
	需要重新生成本地的 <filename>.cf</filename> 文件。
	这一工作可以简单地通过在
	<filename class="directory">/etc/mail</filename>
	目录中执行 <command>make</command>
	<parameter>install</parameter> 来完成。
	接下来， 可以使用 <command>make</command>
	<parameter>restart</parameter> 来重新启动
	<application>Sendmail</application> 服务程序。</para>

      <para>如果一切正常的话， 在
	<filename>/var/log/maillog</filename> 中就不会出现错误提示，
	<application>Sendmail</application> 也应该出现在进程列表中。</para>

      <para>做一个简单的测试， 使用 &man.telnet.1; 来连接邮件服务器：</para>

      <screen>&prompt.root; <userinput>telnet <replaceable>example.com</replaceable> 25</userinput>
Trying 192.0.34.166...
Connected to <hostid role="fqdn">example.com</hostid>.
Escape character is '^]'.
220 <hostid role="fqdn">example.com</hostid> ESMTP Sendmail 8.12.10/8.12.10; Tue, 31 Aug 2004 03:41:22 -0400 (EDT)
<userinput>ehlo <replaceable>example.com</replaceable></userinput>
250-example.com Hello example.com [192.0.34.166], pleased to meet you
250-ENHANCEDSTATUSCODES
250-PIPELINING
250-8BITMIME
250-SIZE
250-DSN
250-ETRN
250-AUTH LOGIN PLAIN
250-STARTTLS
250-DELIVERBY
250 HELP
<userinput>quit</userinput>
221 2.0.0 <hostid role="fqdn">example.com</hostid> closing connection
Connection closed by foreign host.</screen>

      <para>如果输出中出现了 <quote>STARTTLS</quote> 则说明一切正常。</para>
    </sect2>
  </sect1>

  <sect1 id="ipsec">
    <sect1info>
      <authorgroup>
        <author>
  	  <firstname>Nik</firstname>
	  <surname>Clayton</surname>
	  <affiliation>
	    <address><email>nik@FreeBSD.org</email></address>
          </affiliation>
          <contrib>撰写者 </contrib>
        </author>
      </authorgroup>
    </sect1info>

    <indexterm>
      <primary>IPsec</primary>
    </indexterm>

    <title>IPsec 上的 VPN</title>
    <para>使用 FreeBSD 网关在两个被 Internet 分开的网络之间架设 VPN。</para>
 
    <sect2>
      <sect2info>
        <authorgroup>
          <author>
            <firstname>Hiten M.</firstname>
            <surname>Pandya</surname>
	    <affiliation>
	      <address><email>hmp@FreeBSD.org</email></address>
	    </affiliation>
	    <contrib>撰写者 </contrib>
	  </author>
	</authorgroup>
      </sect2info>

      <title>理解 IPsec</title>

      <para>这一节将指导您完成架设 IPsec， 并在一个包含了
	FreeBSD 和 <application>&microsoft.windows; 2000/XP</application>
	机器的网络中使用它来进行安全的通讯的全过程。 为了配置
	IPsec， 您应当熟悉如何编译一个定制的内核的一些概念
	(参见
	<xref linkend="kernelconfig">)。</para>

      <para><emphasis>IPsec</emphasis> 是一种建立在 Internet
	协议 (IP) 层之上的协议。 它能够让两个或更多主机以安全的方式来通讯
	(并因此而得名)。 
	FreeBSD IPsec <quote>网络协议栈</quote> 基于
	<ulink url="http://www.kame.net/">KAME</ulink> 的实现，
	它支持两种协议族， IPv4 和 IPv6。</para>

      <note>
        <para>FreeBSD 5.X 包括了采用 <quote>硬件加速的</quote>
        IPsec 协议栈， 也称作 <quote>Fast
        IPsec</quote>， 它来自 OpenBSD。
        它能够通过 &man.crypto.4; 子系统来利用加密硬件 (只要可能)
        优化 IPSec 的性能。
        这个子系统是新的， 暂时还不支持 KAME 版本的 IPsec
        的全部功能。 此外， 为了启用硬件加速的
        IPsec， 必须把下面的选项加入到内核配置中：</para>

	<indexterm>
	  <primary>内核选项</primary>
	  <secondary>FAST_IPSEC</secondary>
	</indexterm>

        <screen>
options	  FAST_IPSEC  # new IPsec (cannot define w/ IPSEC)
        </screen>

        <para>请注意， 目前还不能把
	  <quote>Fast IPsec</quote> 子系统同 KAME
	  的 IPsec 实现同时混用。 请参考 &man.fast.ipsec.4;
	  联机手册以了解进一步的信息。</para>

      </note>
  
      <indexterm>
	<primary>IPsec</primary>
	<secondary>ESP</secondary>
      </indexterm>
  
      <indexterm>
	<primary>IPsec</primary>
	<secondary>AH</secondary>
      </indexterm>

      <para>IPsec 包括了两个子协议：</para>

      <itemizedlist>
        <listitem>
          <para><emphasis>Encapsulated Security Payload
	      (ESP)</emphasis>, 保护 IP 包数据不被第三方介入，
	    通过使用对称加密算法 (例如 Blowfish、
	    3DES)。</para>
        </listitem>
        <listitem>
          <para><emphasis>Authentication Header (AH)</emphasis>,
	    保护 IP 包头不被第三方介入和伪造，
	    通过计算校验和以及对 IP 包头的字段进行安全散列来实现。
	    随后是一个包含了散列值的附加头，
	    以便能够验证包。</para>
        </listitem>
      </itemizedlist>
      
      <para><acronym>ESP</acronym> 和 <acronym>AH</acronym> 可以根据环境的不同，
	分别或者一同使用。</para>
      
      <indexterm>
	<primary>VPN</primary>
      </indexterm>

      <indexterm>
	<primary>虚拟专用网</primary>
	<see>VPN</see>
      </indexterm>

      <para>IPsec 既可以用来直接加密主机之间的网络通讯
	(也就是 <emphasis>传输模式</emphasis>)； 也可以用来在两个子网之间建造
	<quote>虚拟隧道</quote> 用于两个网络之间的安全通讯
	(也就是 <emphasis>隧道模式</emphasis>)。
	后一种更多的被称为是 <emphasis>虚拟专用网 (VPN)</emphasis>。
	&man.ipsec.4; 联机手册提供了关于 FreeBSD 中 IPsec 子系统的详细信息。</para>

      <para>要把 IPsec 支持放进内核，
	应该在配置文件中加入下面的选项：</para>

      <indexterm>
	<primary>内核选项</primary>
	<secondary>IPSEC</secondary>
      </indexterm>

      <indexterm>
	<primary>内核选项</primary>
	<secondary>IPSEC_ESP</secondary>
      </indexterm>

      <screen>
options   IPSEC        #IP security
options   IPSEC_ESP    #IP security (crypto; define w/ IPSEC)
      </screen>

      <indexterm>
	<primary>内核选项</primary>
	<secondary>IPSEC_DEBUG</secondary>
      </indexterm>

      <para>如果需要 IPsec 的调试支持， 还应增加：</para>

      <screen>
options   IPSEC_DEBUG  #debug for IP security
      </screen>
    </sect2>

    <sect2>
      <title>问题</title>
 
      <para>由于对如何建立 VPN 并不存在标准， 因此 VPN
	可以采用许多种不同的技术来实现， 每种技术都有其长处和弱点。
	这篇文章讲展现一个具体的应用情景， 并为它设计了适合的 VPN。</para>
    </sect2>
    
    <sect2> 
      <title>情景： 两个网络都接入了 Internet， 希望像一个网络那样工作</title>
      
      <indexterm>
	<primary>VPN</primary>
	<secondary>创建</secondary>
      </indexterm>

      <para>现有条件如下：</para>
      
      <itemizedlist>
        <listitem>
          <para>至少有两个不同的站点</para>
        </listitem>
        <listitem>
          <para>每个站点都使用内部的 IP</para>
        </listitem>
        <listitem>
          <para>两个站点都通过运行 FreeBSD 的网关接入 Internet。</para>
        </listitem>
        <listitem>
          <para>每个网络上的网关至少有一个公网的 IP 地址。</para>
        </listitem>
        <listitem>
          <para>网络的内部地址可以是公网或私有的 IP 地址，
            这并不是问题。 如果需要， 还可以在网关上运行 NAT。</para>
        </listitem>
        <listitem>
          <para>两个网络上的 IP 地址
            <emphasis>不冲突</emphasis>。 虽然理论上可以通过
            VPN 和 NAT 连用来使这种情况能够正常工作，
            但那毫无疑问将是管理的噩梦。</para>
        </listitem>
      </itemizedlist>
      
      <para>如果您发现您正打算连接两个内网使用同一私有 IP 地址范围的网络
        (例如它们都使用 <hostid
        role="ipaddr">192.168.1.x</hostid>)， 则其中的一个必须修改网络地址。</para>
 
      <para>网络的拓扑结构如下：</para>
 
      <mediaobject>
	<imageobject>
	  <imagedata fileref="security/ipsec-network" align="center">
	</imageobject>

	<textobject>
<literallayout class="monospaced">
网络 #1            [    内部主机   ]    私有网络，192.168.1.2-254
                   [  Win9x/NT/2K  ]
                   [     UNIX      ]
                            |
                            |
                     .---[fxp1]---.      私有 IP, 192.168.1.1
                     |   FreeBSD  |
                     `---[fxp0]---'      公网 IP, A.B.C.D
                            |
                            |
                   -=-=- Internet -=-=-
                            |
                            |
                     .---[fxp0]---.      公网 IP, W.X.Y.Z
                     |   FreeBSD  |
                     `---[fxp1]---'      私有 IP, 192.168.2.1
                            |
                            |
网络 #2            [ Internal Hosts ]
                   [   Win9x/NT/2K  ]    私有网络， 192.168.2.2-254
                   [      UNIX      ]</literallayout>
	</textobject>
      </mediaobject>
 
      <para>请注意两个公网 IP 地址。 在这篇文章的其余部分我将用这些字母来表示它们。
        在文章中看到这些字母的时候， 请把它们换成自己的公网 IP 地址。
        另外， 在内部， 两个网关都是使用的 .1 的 IP地址，
        而两个网络使用了不同的私有 IP 地址 (相应地， <hostid
        role="ipaddr">192.168.1.x</hostid> 和 <hostid
        role="ipaddr">192.168.2.x</hostid>)。 所有私有网络上的机器都被配置为使用
        <hostid role="ipaddr">.1</hostid> 这台机器作为它们的网关。</para>
 
      <para>我们希望， 从网络的观点看，
        每一个网络上的机器都应该能够像在直接连接到同一路由器上一样看到对方网络上的机器
        -- 尽管可能比路由器略慢一些， 并且有时会有丢包的现象。</para>
 
      <para>这意味着 (举例来说)， 主机 <hostid
        role="ipaddr">192.168.1.20</hostid> 应该能够运行</para>
 
      <programlisting>ping 192.168.2.34</programlisting>

      <para>并且这能够透明地工作。 &windows; 机器应该能够看到其他网络上的机器，
        浏览文件共享， 等等， 就像在本地网络上一样。</para>

      <para>而且这些事情必须是安全的， 也就是说两个网络之间的通讯必须加密。</para>

      <para>在两个网络之间建立 VPN 可以分为几步。
        这些步骤包括：</para>

      <orderedlist>
        <listitem>
          <para>在两个网络之间， 通过 Internet 建立一个
            <quote>虚拟的</quote> 网络连接。
            使用类似 &man.ping.8; 这样的工作来验证它是否正常工作。</para>
        </listitem>

        <listitem>
          <para>在两个网络之间应用安全策略以保证它们之间的通讯被透明地加密盒解密。
            可以使用 &man.tcpdump.1; 或类似的工具来验证这一点。</para>
        </listitem>

        <listitem>
          <para>在 FreeBSD 网关上配置其他软件，
            让 &windows; 机器能够通过 VPN 看到另一个网络中的机器。</para>
        </listitem>
      </orderedlist>

    <sect3>
      <title>步骤 1： 建立并测试 <quote>虚拟的</quote>
        网络连接</title>

      <para>假设您目前已经登录到了网络 #1 的网关机上
        (其公网 IP 地址是 <hostid
        role="ipaddr">A.B.C.D</hostid>， 私网 IP 地址是 <hostid
        role="ipaddr">192.168.1.1</hostid>)， 则您可以执行 <command>ping
        192.168.2.1</command>， 这是公网 IP 为 <hostid role="ipaddr">W.X.Y.Z</hostid>
        的私网地址。 需要做什么实现上述功能呢?</para>

      <orderedlist>
        <listitem>
          <para>作为网关的机器需要知道如何能够到达 <hostid
            role="ipaddr">192.168.2.1</hostid>。 换言之，
            它需要一条通往 <hostid
            role="ipaddr">192.168.2.1</hostid> 的路由。</para>
        </listitem>
        <listitem>
          <para>私网 IP 地址， 例如 <hostid
            role="ipaddr">192.168.x</hostid> 这样的地址是不应在 Internet 上面大量出现的。
            于此相反， 发送到 <hostid role="ipaddr">192.168.2.1</hostid> 的数据包将会封装到另外的包中。
            这样的包对外展现的应该是来自 <hostid role="ipaddr">A.B.C.D</hostid>，
            并被发到 <hostid
            role="ipaddr">W.X.Y.Z</hostid> 去。 这个过程称为
            <firstterm>封装</firstterm>。</para>
        </listitem>
        <listitem>
          <para>一旦包到达了 <hostid
            role="ipaddr">W.X.Y.Z</hostid> 就需要对其
            <quote>拆封</quote>， 并传递给 <hostid
            role="ipaddr">192.168.2.1</hostid>。</para>
	</listitem>
      </orderedlist>
 
      <para>可以把上述过程理解为在两个网络间建立了一个 <quote>隧道</quote>。
        两个 <quote>隧道口</quote> 是 IP 地址 <hostid role="ipaddr">A.B.C.D</hostid>
        和 <hostid role="ipaddr">W.X.Y.Z</hostid>， 而隧道必须被告知哪些私有地址可以自由地在其中通过。
        隧道被用来在公共的 Internet 上传递私有的 IP 数据。</para>
 
      <para>在 FreeBSD 上， 隧道可以通过一般的网络接口， 或
        <devicename>gif</devicename> 来建立。
        您也许已经猜到了， 每一台网关机的 <devicename>gif</devicename>
        接口需要配置四个 IP 地址； 两个是公网 IP 地址，
        另两个则是私网 IP 地址。</para>
 
      <para>对于 gif 设备的支持必须在两台网关机上编译进 &os; 内核。
        可以通过添加下面的设置来达到目的：</para>
 
      <programlisting>pseudo-device gif</programlisting>

      <para>到两边的内核配置文件中， 并重新编译、 安装和启动它们。</para>

      <para>配置隧道可以分为两步来完成。 首先隧道必须被告知外部的
        (或公网的) IP 地址， 可以通过 &man.gifconfig.8; 来完成这步。
        私网 IP 地址则必须使用 &man.ifconfig.8; 来配置。</para>

      <note>
	<para>在 &os;&nbsp;5.X 中，
	  &man.gifconfig.8; 的功能已经并入
	  &man.ifconfig.8;。</para></note>
 
      <para>在网络 #1 的网关机上可以通过下面的两个命令来配置隧道。</para>

      <programlisting>gifconfig gif0 A.B.C.D W.X.Y.Z
ifconfig gif0 inet 192.168.1.1 192.168.2.1 netmask 0xffffffff
      </programlisting>

      <para>在另一边也需要做类似的设置， 只是 IP 地址的顺序是反过来的。</para>

      <programlisting>gifconfig gif0 W.X.Y.Z A.B.C.D
ifconfig gif0 inet 192.168.2.1 192.168.1.1 netmask 0xffffffff
      </programlisting>

      <para>随后执行：</para>

      <programlisting>gifconfig gif0</programlisting>

      <para>可以查看当前的配置情况。 例如， 在网络 #1
        的网关上您应该能够看到：</para>

      <screen>&prompt.root; <userinput>gifconfig gif0</userinput>
gif0: flags=8011&lt;UP,POINTTOPOINT,MULTICAST&gt; mtu 1280
inet 192.168.1.1 --&gt; 192.168.2.1 netmask 0xffffffff
physical address inet A.B.C.D --&gt; W.X.Y.Z
      </screen>

      <para>如您所见， 虽然到已经在物理地址 <hostid role="ipaddr">A.B.C.D</hostid> 和
        <hostid role="ipaddr">W.X.Y.Z</hostid> 之间建立起来，
        而允许通过隧道的地址则是 <hostid
        role="ipaddr">192.168.1.1</hostid> 到 <hostid
        role="ipaddr">192.168.2.1</hostid> 这个范围。</para>

      <para>这同时会在两边机器的路由表中加入一项，
        可以通过 <command>netstat -rn</command> 来观察。
        来自网络 #1的网关机的输出如下。</para>

      <screen>&prompt.root; <userinput>netstat -rn</userinput>
Routing tables

Internet:
Destination      Gateway       Flags    Refs    Use    Netif  Expire
...
192.168.2.1      192.168.1.1   UH        0        0    gif0
...
      </screen>

      <para>正如 <quote>Flags</quote> 的值所显示的那样， 这是一个主机路由，
        这意味着每一个网关都知道如何到达另一端的网关，
        但它们现在还不知道如何到达对方的网络。
        我们接下来立刻解决这个问题。</para>

      <para>您很可能在两台机器上都在运行防火墙。
        这需要作一些变动， 以便适应 VPN 的需要。
        一般来说会希望两个网络相互传递数据包，
        或者通过防火墙来隔离两边的危险。</para>

      <para>如果您将防火墙配置为允许两边的网络传输通过，
        则测试工作会简单不少。 随后您可以随时将限制变得更严格一些。
        假如您在网关上使用 &man.ipfw.8; 则下面的命令</para>

      <programlisting>ipfw add 1 allow ip from any to any via gif0</programlisting>

      <para>将允许两端点的 VPN 数据通过， 而不影响其他防火墙策略。
        很显然， 您需要在两个网关上都执行上述命令。</para>

      <para>现在已经可以让两台机器相互 ping 了。
        在 <hostid role="ipaddr">192.168.1.1</hostid> 您应该能够正常执行</para>

      <programlisting>ping 192.168.2.1</programlisting>

      <para>并得到回应。 对于另一台网关来说也是一样。</para>

      <para>然而， 到目前为止仍然还无法连上另一网络上的内部主机。
        原因是路由 -- 尽管网关机知道如何到达对方那里，
        但它们都不知道如何到达对方后面的网络。</para>

      <para>要解决这个问题， 就必须在两边都添加一条静态路由。
        可以在第一台网关上执行：</para>

      <programlisting>route add 192.168.2.0 192.168.2.1 netmask 0xffffff00
      </programlisting>

      <para>这相当于是说 <quote>为了到达
        <hostid role="ipaddr">192.168.2.0</hostid> 子网的机器，
        需要把包发给 <hostid
        role="ipaddr">192.168.2.1</hostid></quote>。
        您需要在另一个网关上也执行类似的命令， 但使用
        <hostid role="ipaddr">192.168.1.x</hostid> 的地址。</para>

      <para>来自一个网络上的 IP 访问现在能够抵达对面的网络了。</para>

      <para>在两个网络之间建立 VPN 的过程已经完成了三分之二，
        它现在已经是 <quote>虚拟的</quote> <quote>网络</quote>，
        然而它还不够专用。 您可以使用
        &man.ping.8; 和 &man.tcpdump.1; 来进行测试， 并记录两边收发的数据包</para>

      <programlisting>tcpdump dst host 192.168.2.1</programlisting>

      <para>接下来登录到本机的另一个会话</para>

      <programlisting>ping 192.168.2.1</programlisting>

      <para>您将在输出中发现</para>

      <programlisting>
16:10:24.018080 192.168.1.1 &gt; 192.168.2.1: icmp: echo request
16:10:24.018109 192.168.1.1 &gt; 192.168.2.1: icmp: echo reply
16:10:25.018814 192.168.1.1 &gt; 192.168.2.1: icmp: echo request
16:10:25.018847 192.168.1.1 &gt; 192.168.2.1: icmp: echo reply
16:10:26.028896 192.168.1.1 &gt; 192.168.2.1: icmp: echo request
16:10:26.029112 192.168.1.1 &gt; 192.168.2.1: icmp: echo reply
      </programlisting>

      <para>如您所见， ICMP 消息在收发的过程中都没有加密。
       如果使用了 <option>-s</option> 参数来运行
        &man.tcpdump.1;， 甚至可以得到包中的更多信息以及其中的数据。</para>

      <para>很明显这是不能接受的。 下一节将讨论如何让两个网络之间的连接更安全，
        这件事是通过对通讯实施加密来完成的。</para>

      <itemizedlist>
        <title>小结：</title>
        <listitem>
          <para>使用 <quote>pseudo-device
          gif</quote> 配置两边的内核。</para>
        </listitem>
        <listitem>
          <para>编辑网关 #1 上的 <filename>/etc/rc.conf</filename> 并将下面的行添加进去
            (根据需要改 IP )。</para>
          <programlisting>gifconfig_gif0="A.B.C.D W.X.Y.Z"
ifconfig_gif0="inet 192.168.1.1 192.168.2.1 netmask 0xffffffff"
static_routes="vpn"
route_vpn="192.168.2.0 192.168.2.1 netmask 0xffffff00"
          </programlisting>
        </listitem>

        <listitem>
          <para>在两台机器上编辑防火墙脚本
          (<filename>/etc/rc.firewall</filename>， 或类似的名字)
          在其中加入</para>

          <programlisting>ipfw add 1 allow ip from any to any via gif0</programlisting>
        </listitem>
        <listitem>
          <para>在网络 #2 的网关机上也对
            <filename>/etc/rc.conf</filename> 做同样的修改， 注意把 IP 地址倒过来。</para>
        </listitem>
      </itemizedlist>
    </sect3>

    <sect3>
      <title>步骤 2： 对连接实施安全加固</title>

      <para>为了加密连接通讯将用到 IPsec。
        IPsec 提供了一种机制， 使得两台主机协商一个加密密钥，
        并使用它加密之间的通讯。</para>

      <para>在配置时有两个地方需要考虑。</para>

      <orderedlist>
        <listitem>
          <para>必须有能够让两台主机协商所采用的加密方式的机制。
            一旦双方确认了这机制， 则称他们之间建立了
            <quote>安全关联</quote>。</para>
        </listitem>
        <listitem>
          <para>必须采用某种机制来指定哪些通讯需要加密。
            很明显地， 通常并不需要所有的发出数据都被加密
            -- 一般只需要加密在 VPN 上传输的那些数据。
            这类决定哪些数据被加密的规则被称为
            <quote>安全策略</quote>。</para>
         </listitem>
       </orderedlist>
 
       <para>安全关联和安全策略都是由内核来维护的，
         并可以通过用户态的程序来修改。
         在能够这样做之前， 首先需要配置内核来让它支持
         IPsec 和安全载荷封装
         (ESP) 协议。 配置下面的内核选项</para>
 
       <indexterm>
	 <primary>内核选项</primary>
	 <secondary>IPSEC</secondary>
       </indexterm>

       <programlisting>options IPSEC
options IPSEC_ESP
       </programlisting>
 
       <para>然后重新编译、 安装最后重新启动新的内核。
         在继续进行设置之前， 您需要在两台网关上都进行同样的设置。</para>
 
       <indexterm>
	 <primary>IKE</primary>
       </indexterm>

       <para>在建立安全关联时有两种选择。
         一种方法是完全手工地在两台主机之间选择加密算法、 密钥等等，
         另一种方法是使用实现了 Internet 密钥交换协议 (IKE) 的服务程序来帮您完成这些任务。</para>
 
       <para>我们推荐后者。 不说别的， 它配置起来要容易得多。</para>
 
       <indexterm>
	 <primary>IPsec</primary>
	 <secondary>security policies</secondary>
       </indexterm>

       <indexterm>
	 <primary><command>setkey</command></primary>
       </indexterm>

       <para>用  &man.setkey.8; 可以编辑和显示安全策略。
         打个比方， <command>setkey</command> 之于内核的安全策略表，
         就相当于 &man.route.8; 之于内核中的路由表。
         <command>setkey</command> 还可以显示当前的安全关联，
         这一点和 <command>netstat -r</command>
         类似。</para>
 
       <para>FreeBSD 上用于管理安全关联的可供选择的服务程序有很多。
         这篇文章将介绍如何使用其中的一种， racoon。
         racoon 可以从 FreeBSD ports collection 安装，
         它位于 security/ 分类下。 安装方法与其他软件无异。</para>
 
       <indexterm>
	 <primary>racoon</primary>
       </indexterm>

       <para>racoon 需要在两台网关机上都运行。
         需要配置 VPN 另一端的 IP， 以及一个密钥
         (这个密钥可以任意选择， 但两个网关上的密钥必须一致)。</para>
 
       <para>两端的服务程序将相互通讯， 并确认它们各自的身份 (使用刚刚配置的密钥)
         然后服务程序将生成一个新的密钥， 并用它来加密 VPN 上的数据通讯。
         它们定期地改变密钥， 因此即使供给者破解了一个密钥 (虽然这在理论上并不十分可行)
         他也得不到什么 -- 破解密钥的时候， 已经产生一组新的密钥了。</para>
 
       <para>racoon 的配置保存在
         <filename>${PREFIX}/etc/racoon</filename> 中。
         在那里应该能够找到一个配置文件， 不需要修改太多的设置。
         raccon 配置的另一部分， 也就是需要修改的内容，
         是 <quote>预先配置的共享密钥</quote>。</para>
 
       <para>默认的 racoon 配置文件应该可以在
         <filename>${PREFIX}/etc/racoon/psk.txt</filename> 这个文件中找到。
         需要强调的是， 这个密钥 <emphasis>并非</emphasis> 用于加密 VPN 连接的密钥，
         他们只是密钥管理服务程序用以信任对方的一种凭据。</para>

       <para><filename>psk.txt</filename> 包含了需要打交道的每一个远程站点。
         在本例中一共有两个站点， 每一个 <filename>psk.txt</filename> 都只有一行
         (因为每个 VPN 接入点都只和一个端点连接)。</para>
 
       <para>在网关机 #1 上应该是：</para>
 
       <programlisting>W.X.Y.Z            secret</programlisting>
 
       <para>这包括了远程站点的 <emphasis>公网</emphasis> IP 地址，
         空格， 以及提供秘密的字符串。
         很明显不应使用 <quote>secret</quote> 作为实际的密钥 --
         通常的口令选择策略在这里也适用。</para>
 
       <para>在网关 #2 上对应的配置是</para>
 
       <programlisting>A.B.C.D            secret</programlisting>

       <para>也就是说， 对面端的公网 IP 地址， 以及同样的密钥。
         <filename>psk.txt</filename> 的权限必须是
         <literal>0600</literal> (也就是说， 只有
         <username>root</username> 能够读写) 否则 racoon 将不能运行。</para>

       <para>两边的机器上都必须执行 racoon。
         另外， 还需要增加一些防火墙规则来允许 IKE 通讯通过，
         它是通过 UDP 在 ISAKMP (Internet 安全关联密钥管理协议)
         端口上运行的协议。 再次强调， 这个规则应该在规则集尽可能早的位置出现。</para>

       <programlisting>ipfw add 1 allow udp from A.B.C.D to W.X.Y.Z isakmp
ipfw add 1 allow udp from W.X.Y.Z to A.B.C.D isakmp
       </programlisting>

       <para>一旦 racoon 开始运行， 就可以开始测试让网关进行相互的 ping 了。
         此时连接还没有进行加密， 但
         racoon 将在两个主机之间建立安全关联 --
         这可能需要一段时间， 对您来说， 具体的现象则是在 ping 命令开始响应之前会有短暂的延迟。</para>

       <para>一旦安全关联建立之后， 就可以使用 &man.setkey.8； 来查看它了。 在两边的网关上执行</para>

       <programlisting>setkey -D</programlisting>

       <para>就可以看到安全关联的相关信息了。</para>

       <para>现在只完成了一半的工作。 另一半是设置安全策略。</para>

       <para>想要完成一个有判断力的安全策略， 首先要看我们已经完成的步骤。
         接下来的讨论针对连接的两端。</para>

       <para>您所发出的每一个 IP 包都包括一个包头， 其内容是和这个包有关的描述性数据。
         包头包括了包的来源和目的的 IP 地址。
         正如我们所了解的那样， 私有 IP 地址，
         例如 <hostid role="ipaddr">192.168.x.y</hostid>
         这样的地址范围， 不应该出现在 Internet 的公网上。
         于此相反， 他们必须首先封装到别的包中。
         包的来源或目的如果是私有 IP 地址，
         则必须替换成公网 IP 地址。</para>

       <para>因此如果发出的包类似下面这样：</para>

	<mediaobject>
	  <imageobject>
	    <imagedata fileref="security/ipsec-out-pkt" align="center">
	  </imageobject>

	  <textobject>
	    <literallayout class="monospaced">
  .-------------------.
  | Src: 192.168.1.1  |
  | Dst: 192.168.2.1  |
  | &lt;其他头信息    &gt;  |
  +-------------------+
  | &lt;包数据     &gt;     |
  `-------------------'</literallayout>
	  </textobject>
	</mediaobject>

       <para>随后它将被封装进另一个包中， 像下面这样：</para>

	<mediaobject>
	  <imageobject>
	    <imagedata fileref="security/ipsec-encap-pkt" align="center">
	  </imageobject>

	  <textobject>
	    <literallayout class="monospaced">
  .--------------------------.
  | Src: A.B.C.D             |
  | Dst: W.X.Y.Z             |
  | &lt;附加头信息       &gt;      |
  +--------------------------+
  | .----------------------. |
  | | Src: 192.168.1.1     | |
  | | Dst: 192.168.2.1     | |
  | | &lt;附加头信息       &gt;  | |
  | +----------------------+ |
  | | &lt;包数据     &gt;        | |
  | `----------------------' |
  `--------------------------'</literallayout>
	  </textobject>
	</mediaobject>

       <para>封装过程是在
         <devicename>gif</devicename> 设备上完成的。 如上图所示，
         包现在有了外部的实际 IP 地址， 而原始的包则被封装到里面作为数据。
         这个包将通过 Internet 传递。</para>

       <para>很明显地， 我们希望 VPN 之间的通讯是加密的。
         用语言来描述大致是：</para>

       <para><quote>如果包从 <hostid
         role="ipaddr">A.B.C.D</hostid> 发出且其目的地是 <hostid
         role="ipaddr">W.X.Y.Z</hostid>， 则通过必要的安全关联进行加密。</quote></para>

       <para><quote>如果包来自 <hostid
         role="ipaddr">W.X.Y.Z</hostid> 且其目的地是 <hostid
         role="ipaddr">A.B.C.D</hostid>， 则通过必要的安全关联进行解密。</quote></para>

       <para>这已经很接近了， 但还不够正确。 如果这么做的话，
         所有来自和发到 <hostid role="ipaddr">W.X.Y.Z</hostid> 的包，
         无论是否属于 VPN 通讯都会被加密。 这可能并不是您所希望的，
         因此正确的安全策略应该是</para>

       <para><quote>如果包从 <hostid
         role="ipaddr">A.B.C.D</hostid> 发出， 且封装了其他的包，
         其目的地是 <hostid
         role="ipaddr">W.X.Y.Z</hostid>， 则通过必要的安全关联进行加密。</quote></para>

       <para><quote>如果包来自 <hostid
         role="ipaddr">W.X.Y.Z</hostid>， 且封装了其他的包，
         其目的地是 <hostid
         role="ipaddr">A.B.C.D</hostid>， 则通过必要的安全关联进行解密。</quote></para>

       <para>一个很小， 但却必要的改动。</para>

       <para>安全策略也是通过 &man.setkey.8; 设置的。
         &man.setkey.8; 提供了一种用于配置策略的语言。
         可以直接在 stdin 上输入策略， 或通过 <option>-f</option>
         选项来指定一个包含配置命令的文件。</para>

       <para>网关 #1 上的配置 (其
         IP 地址是 <hostid role="ipaddr">A.B.C.D</hostid>) 强制将所有到
         <hostid role="ipaddr">W.X.Y.Z</hostid> 的通讯进行加密的配置是：</para>

       <programlisting>
spdadd A.B.C.D/32 W.X.Y.Z/32 ipencap -P out ipsec esp/tunnel/A.B.C.D-W.X.Y.Z/require;
       </programlisting>
 
       <para>把这些命令放到一个文件 (例如
       <filename>/etc/ipsec.conf</filename>) 然后执行</para>

       <screen>&prompt.root; <userinput>setkey -f /etc/ipsec.conf</userinput></screen>

       <para><option>spdadd</option> 会告诉 &man.setkey.8; 我们希望把规则加入到安全策略数据库中。
         命令的其它部分指定了什么样的包能够匹配这规则。
         <hostid role="ipaddr">A.B.C.D/32</hostid> 和 <hostid
         role="ipaddr">W.X.Y.Z/32</hostid> 是用于指定规则能够匹配的网络或主机的
         IP 地址和掩码。 本例中， 希望应用到两个主机之间的通讯上。
         <option>ipencap</option> 则告诉内核这规则只应被用于封装其他包的那些数据包。
         <option>-P out</option> 表示策略是针对发出的包的， 而
         <option>ipsec</option> 则表示需要对数据包进行加密。</para>

       <para>第二行指定了如何加密。
         <option>esp</option> 是将要使用的协议，
         而 <option>tunnel</option> 则表示包应该进一步封装进一个
         IPsec 包里面。 反复使用
         <hostid role="ipaddr">A.B.C.D</hostid> 和 <hostid
         role="ipaddr">W.X.Y.Z</hostid> 用来选择所用的安全关联
         而最后的 <option>require</option> 则强制所有匹配这规则的包都被加密。</para>

       <para>上面的规则只匹配了发出的包。 接下来需要配置类似的匹配进入包的规则。</para>

       <programlisting>spdadd W.X.Y.Z/32 A.B.C.D/32 ipencap -P in ipsec esp/tunnel/W.X.Y.Z-A.B.C.D/require;</programlisting>

       <para>请注意本例中 <option>in</option> 代替了
         <option>out</option> 并且 IP 地址的顺序也相反。</para>

       <para>在另一个网关上 (其公网 IP 地址是
         <hostid role="ipaddr">W.X.Y.Z</hostid>) 也需要类似的规则。</para>

       <programlisting>spdadd W.X.Y.Z/32 A.B.C.D/32 ipencap -P out ipsec esp/tunnel/W.X.Y.Z-A.B.C.D/require;
spdadd A.B.C.D/32 W.X.Y.Z/32 ipencap -P in ipsec esp/tunnel/A.B.C.D-W.X.Y.Z/require;</programlisting>
 
       <para>最后是添加允许 ESP 和
        IPENCAP 包进出的防火墙规则。 这些规则需要在两边分别设置。</para>

       <programlisting>ipfw add 1 allow esp from A.B.C.D to W.X.Y.Z
ipfw add 1 allow esp from W.X.Y.Z to A.B.C.D
ipfw add 1 allow ipencap from A.B.C.D to W.X.Y.Z
ipfw add 1 allow ipencap from W.X.Y.Z to A.B.C.D
       </programlisting>

       <para>由于规则的对称性， 因此可以在两台网关上使用同样的规则。</para>

       <para>发出的包如下图所示：</para>

	<mediaobject>
	  <imageobject>
	    <imagedata fileref="security/ipsec-crypt-pkt" align="center">
	  </imageobject>

	  <textobject>
	    <literallayout class="monospaced">
  .------------------------------.  --------------------------.
  | Src: A.B.C.D                 |                            |
  | Dst: W.X.Y.Z                 |                            |
  | &lt;other header info&gt;          |                            |  Encrypted
  +------------------------------+                            |  packet.
  | .--------------------------. |  -------------.            |  contents
  | | Src: A.B.C.D             | |               |            |  are
  | | Dst: W.X.Y.Z             | |               |            |  completely
  | | &lt;other header info&gt;      | |               |            |- secure
  | +--------------------------+ |               |  Encap'd   |  from third
  | | .----------------------. | |  -.           |  packet    |  party
  | | | Src: 192.168.1.1     | | |   |  Original |- with real |  snooping
  | | | Dst: 192.168.2.1     | | |   |  packet,  |  IP addr   |
  | | | &lt;other header info&gt;  | | |   |- private  |            |
  | | +----------------------+ | |   |  IP addr  |            |
  | | | &lt;packet data&gt;        | | |   |           |            |
  | | `----------------------' | |  -'           |            |
  | `--------------------------' |  -------------'            |
  `------------------------------'  --------------------------'
	    </literallayout>
	  </textobject>
	</mediaobject>

       <para>当 VPN 数据被远端接到时， 它将首先被解密
         (使用 racoon 协商得到的安全关联)。
         然后它们将进入
         <devicename>gif</devicename> 接口， 并在那里展开第二层，
         直到只剩下最里层的包， 并将其转发到内网上。</para>

       <para>可以通过与之前同样的 &man.ping.8; 命令来测试安全性。
         首先登录到
         <hostid role="ipaddr">A.B.C.D</hostid> 网关上并执行：</para>

       <programlisting>tcpdump dst host 192.168.2.1</programlisting>

       <para>在同一主机上登录另一会话， 执行</para>

       <programlisting>ping 192.168.2.1</programlisting>

       <para>此时的输出应该是：</para>

       <programlisting>XXX tcpdump output</programlisting>

       <para>如您看到的， &man.tcpdump.1; 给出的将是 ESP 包。
         假如您想查看它们的内容可以使用 <option>-s</option> option 选项，
         您将 (显然地) 看到一些乱码， 因为传输过程实施了加密。</para>

      <para>祝贺您。 您已经完成了两个远程站点之间的 VPN 的架设工作。</para>

      <itemizedlist>
        <title>小结</title>
        <listitem>
          <para>将两边的内核配置加入：</para>

          <programlisting>options IPSEC
options IPSEC_ESP
          </programlisting>
        </listitem>
        <listitem>
          <para>安装 <filename
            role="package">security/racoon</filename>。 编辑两台网关上的
            <filename>${PREFIX}/etc/racoon/psk.txt</filename>
            并添加远程主机的 IP 和共享的密钥。 文件的权限应该是 0600。</para>
        </listitem>
        <listitem>
          <para>将下面的设置加入两台主机的
            <filename>/etc/rc.conf</filename> 中：</para>

          <programlisting>ipsec_enable="YES"
ipsec_file="/etc/ipsec.conf"
          </programlisting>
        </listitem>
        <listitem>
          <para>在两个网关上都建立 <filename>/etc/ipsec.conf</filename>
            并添加必要的 spdadd。 在网关 #1 上是：</para>

          <programlisting>
spdadd A.B.C.D/32 W.X.Y.Z/32 ipencap -P out ipsec
  esp/tunnel/A.B.C.D-W.X.Y.Z/require;
spdadd W.X.Y.Z/32 A.B.C.D/32 ipencap -P in ipsec
  esp/tunnel/W.X.Y.Z-A.B.C.D/require;
</programlisting>

          <para>在网关 #2 上则是：</para>

<programlisting>
spdadd W.X.Y.Z/32 A.B.C.D/32 ipencap -P out ipsec
  esp/tunnel/W.X.Y.Z-A.B.C.D/require;
spdadd A.B.C.D/32 W.X.Y.Z/32 ipencap -P in ipsec
  esp/tunnel/A.B.C.D-W.X.Y.Z/require;
</programlisting>
        </listitem>
        <listitem>
          <para>添加防火墙规则以允许 IKE, ESP, 和 IPENCAP
            通讯能够到达各自的主机：</para>

          <programlisting>
ipfw add 1 allow udp from A.B.C.D to W.X.Y.Z isakmp
ipfw add 1 allow udp from W.X.Y.Z to A.B.C.D isakmp
ipfw add 1 allow esp from A.B.C.D to W.X.Y.Z
ipfw add 1 allow esp from W.X.Y.Z to A.B.C.D
ipfw add 1 allow ipencap from A.B.C.D to W.X.Y.Z
ipfw add 1 allow ipencap from W.X.Y.Z to A.B.C.D
          </programlisting>
        </listitem>
      </itemizedlist>

      <para>前面的两步应该足以让 VPN 运转起来了。
        两个网络上的机器都应该能通过 IP 来访问对方，
        而所有的通讯都被自动地进行加密。</para>
    </sect3>
    </sect2>
  </sect1>

  <sect1 id="openssh">
    <sect1info>
      <authorgroup>
	<author>
	  <firstname>Chern</firstname>
	  <surname>Lee</surname>
	  <contrib>原著 </contrib>
	</author>
	<!-- 21 April 2001 -->
      </authorgroup>
    </sect1info>

    <title>OpenSSH</title>
    <indexterm><primary>OpenSSH</primary></indexterm>
    <indexterm>
      <primary>安全</primary>
      <secondary>OpenSSH</secondary>
    </indexterm>

    <para><application>OpenSSH</application> 是一组用于安全地访问远程计算机的连接工具。
      它可以作为 <command>rlogin</command>、
      <command>rsh</command> <command>rcp</command> 以及
      <command>telnet</command> 的直接替代品使用。
      更进一步， 其他任何 TCP/IP 连接都可以通过 SSH 安全地进行隧道/转发。
      <application>OpenSSH</application> 对所有的传输进行加密，
      从而有效地阻止了窃听、 连接劫持， 以及其他网络级的攻击。</para>

    <para><application>OpenSSH</application> 由 OpenBSD project 维护， 它基于
      SSH v1.2.12 并包含了最新的错误修复和更新。
      它同时兼容 SSH 协议的 1 和 2 两个版本。
      从 FreeBSD&nbsp;4.0 开始， <application>OpenSSH</application> 成为了基本系统的一部分。</para>

    <sect2>
      <title>使用 OpenSSH 的好处</title>

      <para>通常，当使用 &man.telnet.1; 或 &man.rlogin.1; 时，
        数据是以明码的形式发送的，并没有加密。
        在客户机和服务器之间的网络上运行的听包程序可以在会话中偷窃到传输的用户名/密码和数据。
        <application>OpenSSH</application> 提供了多种的身份验证和加密方法来防止这种情况的发生。</para>
    </sect2>

    <sect2>
      <title>启用 sshd</title>
      <indexterm>
        <primary>OpenSSH</primary>
        <secondary>启用</secondary>
      </indexterm>

      <para>确信已将下面这行加入了
        <filename>rc.conf</filename> 文件：</para>
      <screen>sshd_enable="YES"</screen>
      <para>将在下次启动系统时加载 <application>OpenSSH</application> 的 &man.sshd.8; 服务程序。
	另外， 也可以简单地使用 <command>sshd</command> 来直接启动
	<application>sshd</application> 服务。</para>
    </sect2>

    <sect2>
      <title>SSH 客户</title>
      <indexterm>
        <primary>OpenSSH</primary>
        <secondary>客户</secondary>
      </indexterm>

      <para>&man.ssh.1; 的工作方式和
        &man.rlogin.1; 非常类似。</para>

      <screen>&prompt.root; <userinput>ssh <replaceable>user@example.com</replaceable></userinput>
Host key not found from the list of known hosts.
Are you sure you want to continue connecting (yes/no)? <userinput>yes</userinput>
Host 'example.com' added to the list of known hosts.
user@example.com's password: <userinput>*******</userinput></screen>

      <para>登录过程和使用
        <command>rlogin</command> 或
        <command>telnet</command> 建立的会话非常类似。
        在连接时， SSH 会利用一个密钥指纹系统来验证服务器的真实性。
        只有在第一次连接时， 用户会被要求输入
	<literal>yes</literal>。 之后的连接将会验证预先保存下来的密钥指纹。
        如果保存的指纹与登录时接收到的不符， 则将会给出警告。
        指纹保存在 <filename>~/.ssh/known_hosts</filename> 中， 对于 SSH v2 指纹， 则是
	<filename>~/.ssh/known_hosts2</filename>。</para>

      <para>默认情况下， <application>OpenSSH</application> 服务器只接受
	SSH v2 连接。 然而， 客户端可以自行选择协议的版本 1 和 2 之一。
	广为人知的一个事实是， 第 2 版的协议要更加健壮和安全。</para>

      <para>通过 <option>-1</option> 或 <option>-2</option> 参数，
	可以强制 &man.ssh.1; 使用 v1 或 v2 的协议。</para>
    </sect2>

    <sect2>
      <title>安全复制</title>
      <indexterm>
        <primary>OpenSSH</primary>
        <secondary>安全复制</secondary>
      </indexterm>
      <indexterm><primary><command>scp</command></primary></indexterm>

      <para>&man.scp.1; 命令和
	&man.rcp.1;; 的用法类似， 它用于将文件复制到远程的机器上， 或复制过来，
	区别是它是安全的。</para>

      <screen>&prompt.root; <userinput> scp <replaceable>user@example.com:/COPYRIGHT COPYRIGHT</replaceable></userinput>
user@example.com's password: <userinput>*******</userinput>
COPYRIGHT            100% |*****************************|  4735
00:00
&prompt.root;</screen>
      <para>由于先前的例子中已经保存了指纹， 使用 &man.scp.1;
        时会自动地加以验证。</para>

      <para>&man.scp.1; 使用的参数同
	&man.cp.1; 类似。 第一个参数是一个或一组文件，
	然后是复制的目标。 由于文件是通过 SSH 在网上传递的，
	因此某些文件的名字需要写成
	<option>用户名@主机名:&lt;远程文件路径&gt;</option>。</para>

    </sect2>

    <sect2>
      <title>配置</title>
      <indexterm>
        <primary>OpenSSH</primary>
        <secondary>配置</secondary>
      </indexterm>

      <para>针对 <application>OpenSSH</application>
        服务程序和客户端的系统级配置文件在 <filename>/etc/ssh</filename>
        目录中。</para>

      <para><filename>ssh_config</filename> 用于配置客户端的设定，
        而 <filename>sshd_config</filename> 则用于配置服务器端。</para>

      <para>另外 <option>sshd_program</option>
	(默认是 <filename>/usr/sbin/sshd</filename>)， 以及
	<option>sshd_flags</option> 这两个 <filename>rc.conf</filename>
	选项提供了更多的配置选择。</para>
    </sect2>

    <sect2>
      <title>ssh-keygen</title>

      <para>&man.ssh-keygen.1; 可以被用来生成
        RSA 密钥对来代替使用口令验证用户的身份：</para>

      <screen>&prompt.user; <userinput>ssh-keygen -t <replaceable>rsa1</replaceable></userinput>
Initializing random number generator...
Generating p:  .++ (distance 66)
Generating q:  ..............................++ (distance 498)
Computing the keys...
Key generation complete.
Enter file in which to save the key (/home/user/.ssh/identity):
Enter passphrase:
Enter the same passphrase again:
Your identification has been saved in /home/user/.ssh/identity.
...</screen>

      <para>&man.ssh-keygen.1; 将产生一个公私密钥对来用于验证身份。
        私钥被保存到
        <filename>~/.ssh/identity</filename>， 而公钥则保存到
        <filename>~/.ssh/identity.pub</filename>。
        远程机器上的 <filename>~/.ssh/authorized_keys</filename>
        中必须有对应的公钥， 才能够完成身份验证过程。</para>

      <para>这将允许从远程以基于 RSA 的验证来代替口令验证连接到本机上。</para>

      <note><para>使用 <option>-t rsa1</option> 这个选项将创建用于 第1版 SSH 协议的
	RSA 密钥对。 如果您希望使用用于 SSH 第2版协议的 RSA密钥对， 则应使用
	<command>ssh-keygen -t rsa</command> 这个命令。</para></note>

      <para>如果在 &man.ssh-keygen.1; 中使用了通行字，
        则每次使用私钥时都需要输入它。</para>

      <para>另外， 还可以使用 <command>ssh-keygen -t dsa</command> 来创建一个用于第2版
	SSH 协议的 DSA 密钥。
	这将生成一对 DSA 公/私钥， 并且只能用于第2版的 SSH 协议会话。
	公钥将保存为 <filename>~/.ssh/id_dsa.pub</filename>,
	而私钥保存为 <filename>~/.ssh/id_dsa</filename>。</para>

      <para>DSA 公钥也应该放到远程主机的
	<filename>~/.ssh/authorized_keys</filename> 里面。</para>

      <para>&man.ssh-agent.1; 和 &man.ssh-add.1; 是用于管理多个受密码保护的私钥的工具。</para>

      <warning><para>随版本的不同， <application>OpenSSH</application>
	可能会使用不同的文件和选项。
	为了避免出现问题， 请参考 &man.ssh-keygen.1; 联机手册。</para></warning>
    </sect2>

    <sect2 id="security-ssh-tunneling">
      <title>SSH 隧道</title>
      <indexterm>
        <primary>OpenSSH</primary>
        <secondary>隧道</secondary>
      </indexterm>

      <para><application>OpenSSH</application> 能够创建隧道以便用加密的会话来封装其他协议。</para>

      <para>下面的命令告诉 &man.ssh.1; 为 <application>telnet</application> 创建一个隧道：</para>

       <screen>&prompt.user; <userinput>ssh -2 -N -f -L <replaceable>5023:localhost:23 user@foo.example.com</replaceable></userinput>
&prompt.user;</screen>

      <para>上述 <command>ssh</command> 命令使用了下面这些选项：</para>

      <variablelist>
	<varlistentry>
	  <term><option>-2</option></term>

	  <listitem>
	    <para>强制 <command>ssh</command> 使用第2版的协议
	      (如果需要和较老的 SSH 一同工作请不要使用这个选项)。</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><option>-N</option></term>

	  <listitem>
	    <para>表示不使用命令行， 或者说只使用隧道。 如果省略，
	      <command>ssh</command> 将同时初始化会话。</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><option>-f</option></term>

	  <listitem>
	    <para>强制 <command>ssh</command> 在后台执行。</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><option>-L</option></term>

	  <listitem>
	    <para>表示产生一条
	      <replaceable>本地端口:远程主机:远程端口</replaceable>
	      形式的隧道。</para>
	  </listitem>
	  </varlistentry>

	<varlistentry>
	  <term><option>user@foo.example.com</option></term>

	  <listitem>
	    <para>远程 SSH 服务器。</para>
	  </listitem>
	</varlistentry>
      </variablelist>


      <para>SSH 隧道通过监听
	<hostid>localhost</hostid> 上面指定端口来完成工作。
	它将把本机主机/端口上接收到的连接通过 SSH 连接转发到远程主机/端口。</para>

      <para>本例中， 位于 <hostid>localhost</hostid> 的 <replaceable>5023</replaceable> 端口
	被用于转发 <hostid>localhost</hostid> 的连接到远程主机的
	<replaceable>23</replaceable> 端口。
	由于 <replaceable>23</replaceable> 是 <application>telnet</application> 使用的，
	因此它将通过 SSH 隧道完成 <application>telnet</application> 会话。</para>

      <para>这可以用来封装任意不安全的 TCP 协议， 例如
        SMTP、 POP3、 FTP等等。</para>

      <example>
	<title>使用 SSH 为 SMTP 创建安全隧道</title>

        <screen>&prompt.user; <userinput>ssh -2 -N -f -L <replaceable>5025:localhost:25 user@mailserver.example.com</replaceable></userinput>
user@mailserver.example.com's password: <userinput>*****</userinput>
&prompt.user; <userinput>telnet localhost 5025</userinput>
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 mailserver.example.com ESMTP</screen>

        <para>这可以与
          &man.ssh-keygen.1; 以及额外的用户帐号配合来建立一个更透明的 SSH
          隧道环境。 密钥可以被用在需要输入口令的地方， 而且可以为不同的用户配置不同的隧道。</para>
      </example>

      <sect3>
	<title>实用的 SSH 通道例子</title>

	<sect4>
	  <title>加强 POP3 服务的安全</title>

	  <para>工作时， 有一个允许外来连接的 SSH 服务器。
	    同一个办公网络中有一个邮件服务器提供 POP3 服务。
	    这个网络， 或从您家到办公室的网络可能不，
	    或不完全可信。 基于这样的原因，
	    您需要以安全的方式来察看邮件。
	    解决方法是创建一个到办公室 SSH 服务器的连接，
	    并通过这个连接来访问 POP3 服务：</para>

	  <screen>&prompt.user; <userinput>ssh -2 -N -f -L <replaceable>2110:mail.example.com:110 user@ssh-server.example.com</replaceable></userinput>
user@ssh-server.example.com's password: <userinput>******</userinput></screen>

	  <para>当这个通道连上时， 您可以把 POP3 请求发到
	    <hostid>localhost</hostid> 端口 2110。
	    这个连接将通过通道安全地转发到
	    <hostid>mail.example.com</hostid>。</para>
	</sect4>

	<sect4>
	  <title>绕过严厉的防火墙</title>

	  <para>一些大脑长包的网络管理员会使用一些极端的防火墙策略，
	    不仅过滤进入的连接， 而且也过滤连出的连接。
	    一些时候您可能只能连接远程机器 22 端口，以及 80 端口用来进行
	    SSH 和网页浏览。</para>

	  <para>您可能希望访问一些其它的 (也许与工作无关的) 服务，
	    例如提供音乐的 Ogg Vorbis 流媒体服务器。
	    如果 Ogg Vorbis server 在 22 或 80 端口以外的端口播放音乐，
	    则您将无法访问它。</para>

	  <para>解决方法是建立一个到您的网络的防火墙之外的网络上的 SSH
	    服务器， 并通过它提供的通道连接到 Ogg Vorbis 服务器上。</para>

	  <screen>&prompt.user; <userinput>ssh -2 -N -f -L <replaceable>8888:music.example.com:8000 user@unfirewalled-system.example.org</replaceable></userinput>
user@unfirewalled-system.example.org's password: <userinput>*******</userinput></screen>

	  <para>现在您可以把客户程序指定到
	    <hostid>localhost</hostid> 的 8888 端口， 它将把请求转发给
	    <hostid>music.example.com</hostid> 的 8000
	    端口， 从而绕过防火墙。</para>
        </sect4>
      </sect3>
    </sect2>

    <sect2>
      <title>进一步的资料</title>
      <para><ulink url="http://www.openssh.com/">OpenSSH</ulink></para>
      <para>&man.ssh.1; &man.scp.1; &man.ssh-keygen.1;
        &man.ssh-agent.1; &man.ssh-add.1;</para>
      <para>&man.sshd.8; &man.sftp-server.8;</para>
    </sect2>
  </sect1>

  <sect1 id="fs-acl">
    <sect1info>
      <authorgroup>
	<author>
	  <firstname>Tom</firstname>
	  <surname>Rhodes</surname>
	  <contrib>作者 </contrib>
	</author>
      </authorgroup>
    </sect1info>
    <indexterm>
      <primary>ACL</primary>
    </indexterm>
    <title>文件系统访问控制表</title>

    <para>与文件系统在其他方面的加强， 如快照等一道， FreeBSD 5.0
      及更高版本提供了通过文件系统访问控制表
      (<acronym>ACLs</acronym>) 实现的安全机制。</para>

    <para>访问控制表以高度兼容 (&posix;.1e) 的方式扩展了标准的 &unix;
      权限模型。 这一特性使得管理员能够利用其优势设计更为复杂的安全模型。</para>

    <para>如果想为 <acronym>UFS</acronym> 文件系统启用 <acronym>ACL</acronym>
      支持， 则需要添加下列选项：</para>

    <programlisting>options UFS_ACL</programlisting>

    <para>并重新编译内核。 如果这个选项没有编译进内核，
      则在挂接支持 <acronym>ACL</acronym> 的文件系统时将会收到警告。
      这个选项在 <filename>GENERIC</filename> 内核中已经包含了。
      <acronym>ACL</acronym> 依赖于在文件系统上启用扩展属性。
      在新一代的
      &unix; file system， <acronym>UFS2</acronym> 中内建了这种支持。</para>

    <note><para>在 <acronym>UFS1</acronym> 上配置扩展属性需要比 <acronym>UFS2</acronym>
      更多的管理开销。 而且， 在 <acronym>UFS2</acronym>
      上的扩展属性的性能也有极大的提高。
      因此， 如果想要使用访问控制表， 推荐使用 <acronym>UFS2</acronym>
      而不是 <acronym>UFS1</acronym>。</para></note>

    <para><acronym>ACL</acronym> 可以在挂接时通过选项
      <option>acls</option> 来启动， 它可以加入 <filename>/etc/fstab</filename>。
      另外， 也可以通过使用 &man.tunefs.8; 修改超级块中的 <acronym>ACL</acronym>
      标记来持久性地设置自动的挂接属性。 一般而言， 后一种方法是推荐的做法，
      其原因是：</para>

    <itemizedlist>
      <listitem>
	<para>挂接时的 <acronym>ACL</acronym> 标记无法被重挂接
	(&man.mount.8; <option>-u</option>) 改变， 只有完整地
	&man.umount.8; 并做一次新的 &man.mount.8; 才能改变它。
	这意味着 <acronym>ACLs</acronym> 状态在系统启动之后就不可能在 root 文件系统上发生变化了。
	另外也没有办法改变正在使用的文件系统的这个状态。</para>
      </listitem>

      <listitem>
	<para>在超级块中的设置将使得文件系统总被以启用
	<acronym>ACLs</acronym> 的方式挂接， 即使在
	<filename>fstab</filename> 中的对应项目没有作设置， 或设备顺序发生变化时也是如此。
	这避免了不慎将文件系统以没有启用 <acronym>ACLs</acronym> 的状态挂接，
	从而避免没有强制 <acronym>ACLs</acronym> 这样的安全问题。</para>
      </listitem>
    </itemizedlist>

    <note><para>可以修改 <acronym>ACL</acronym> 行为， 以允许在没有执行一次全新的
      &man.mount.8; 的情况下启用它， 但我们认为不鼓励在不启用
      <acronym>ACL</acronym> 的时候这么做是有必要的， 因为如果启用了
      <acronym>ACL</acronym>， 然后关掉它， 然后在没有刷新扩展属性的情况下重新启用它是很容易造成问题的。
      一般而言， 一旦启用了文件系统的 <acronym>ACLs</acronym> 就不应该再关掉它，
      因为此时的文件系统的保护措施可能和用户所期待的样子不再兼容，
      而重新启用 <acronym>ACL</acronym> 将重新把先前的
      <acronym>ACL</acronym> 附着到文件上， 而由于它们的权限发生了变化，
      就很可能造成无法预期的行为。</para></note>

    <para>在察看目录时， 启用了 <acronym>ACLs</acronym> 的文件将在通常的属性后面显示 <literal>+</literal>
      (加号)。 例如：</para>

    <programlisting>drwx------  2 robert  robert  512 Dec 27 11:54 private
drwxrwx---+ 2 robert  robert  512 Dec 23 10:57 directory1
drwxrwx---+ 2 robert  robert  512 Dec 22 10:20 directory2
drwxrwx---+ 2 robert  robert  512 Dec 27 11:57 directory3
drwxr-xr-x  2 robert  robert  512 Nov 10 11:54 public_html</programlisting>

    <para>这里我们看到了 <filename>directory1</filename>,
      <filename>directory2</filename>， 以及 <filename>directory3</filename>
      目录使用了 <acronym>ACLs</acronym>。 而
      <filename>public_html</filename> 则没有。</para>

    <sect2>
      <title>使用 <acronym>ACL</acronym></title>

      <para>文件系统 <acronym>ACL</acronym> 可以使用
	&man.getfacl.1; 工具来查看。 例如， 如果想查看 <filename>test</filename> 的
	<acronym>ACL</acronym> 设置， 所用的命令是：</para>

      <screen>&prompt.user; <userinput>getfacl <filename>test</filename></userinput>
	#file:
	#owner:1001
	#group:1001
	user::rw-
	group::r--
	other::r--</screen>

      <para>要修改这个文件上的 <acronym>ACL</acronym> 设置，
	则需要使用 &man.setfacl.1; 工具。 例如：</para>

      <screen>&prompt.user; <userinput>setfacl -k <filename>test</filename></userinput></screen>

      <para><option>-k</option> 参数将把所有当前定义的
	<acronym>ACL</acronym> 从文件或文件系统中删除。
	一般来说应该使用 <option>-b</option> 因为它会保持让
	<acronym>ACL</acronym> 正常工作的那些项不变。</para>

      <screen>&prompt.user; <userinput>setfacl -m u:trhodes:rwx,group:web:r--,o::--- <filename>test</filename></userinput></screen>

      <para>在前面的命令中， <literal>-m</literal>
	选项被用来修改默认的 <acronym>ACL</acronym> 项。由于已经被先前的命令
	删除，因此没有预先定义的项，于是默认的选项被恢复，并附加上指定的选项。
	请小心地检查，如果您加入了一个不存在的用户或组，那么将会在
	<devicename>stdout</devicename> 得到一条 <errorname>Invalid argument</errorname>
	的错误提示。</para>
    </sect2>
  </sect1>

  <sect1 id="security-portaudit">
    <sect1info>
      <authorgroup>
	<author>
	  <firstname>Tom</firstname>
	  <surname>Rhodes</surname>
	  <contrib>Contributed by </contrib>
	</author>
      </authorgroup>
    </sect1info>

    <indexterm>
      <primary>Portaudit</primary>
    </indexterm>
    <title>监视第三方安全问题</title>

    <para>过去几年中， 安全领域在如何处理漏洞的评估方面取得了长足的进步。
      几乎每一个操作系统都越来越多地安装和配置了第三方工具，
      而系统被入侵的威胁也随之增加。</para>

    <para>漏洞的评估是安全的一个关键因素，
      尽管 &os; 会发布基本系统的安全公告，
      然而为每一个第三方工具都发布安全公告则超出了 &os; Project
      的能力。 在这一前提下， 一种减轻第三方漏洞的威胁，
      并警告管理员存在已知的安全问题的方法也就应运而生。 名为
      <application>Portaudit</application> 的 &os; 附加工具能够帮助您达成这一目的。</para>

    <para><filename role="port">security/portaudit</filename> port
      会下载一个数据库， 这一数据库是由 &os; Security
      Team 和 ports 开发人员维护的， 其中包含了已知的安全问题。</para>

    <para>要开始使用 <application>Portaudit</application>，
      需要首先从 Ports Collection 安装它：</para>

    <screen>&prompt.root; <userinput>cd /usr/ports/security/portaudit && make install clean</userinput></screen>

    <para>在安装过程中，
      &man.periodic.8; 的配置文件将被修改， 以便让
      <application>Portaudit</application> 能够在每天的安全审计过程中运行。
      不需要进行更多的配置了。</para>

    <para>安装完成之后， 管理员必须通过运行下面的命令，
      来更新保存在本地
      <filename role="directory">/var/db/portaudit</filename> 的数据库：</para>

    <screen>&prompt.root; <userinput>portaudit -F</userinput></screen>

    <note>
      <para>由于每天执行
	&man.periodic.8; 时都会自动更新数据库， 因此，
	运行这条命令是可选的。 在这里只是作为例子给出。</para>
    </note>

    <para>管理员可以使用下面的命令审计通过 Ports Collection
      安装的第三方工具：</para>

    <screen>&prompt.root; <userinput>portaudit -a</userinput></screen>

    <para>下面是一个示范的输出：</para>

    <programlisting>Affected package: cups-base-1.1.22.0_1
Type of problem: cups-base -- HPGL buffer overflow vulnerability.
Reference: &lt;http://www.FreeBSD.org/ports/portaudit/40a3bca2-6809-11d9-a9e7-0001020eed82.html&gt;

1 problem(s) in your installed packages found.

You are advised to update or deinstall the affected package(s) immediately.</programlisting>

    <para>通过访问上面给出的 <acronym>URL</acronym>，
      管理员能够了解关于那个漏洞的进一步信息。
      这些信息通常包括受到影响的 &os; Port 版本，
      以及其他可能包含安全公告的网站。</para>

    <para>简而言之， <application>Portaudit</application>
      是一个强大的工具， 并能够配合
      <application>Portupgrade</application> port
      来非常有效地工作。</para>
  </sect1>

  <sect1 id="security-advisories">
    <sect1info>
      <authorgroup>
	<author>
	  <firstname>Tom</firstname>
	  <surname>Rhodes</surname>
	  <contrib>作者 </contrib>
	</author>
      </authorgroup>
    </sect1info>
    <indexterm>
      <primary>FreeBSD 安全公告</primary>
    </indexterm>
    <title>&os; 安全公告</title>

    <para>像其它具有产品级品质的操作系统一样， &os; 会发布
      <quote>安全公告</quote>。
      通常这类公告会只有在在相应的发行版本已经正确地打过补丁之后发到安全邮件列表并在勘误中说明。
      本节将介绍什么是安全公告， 如何理解它， 以及为系统打补丁的具体步骤。</para>

    <sect2>
      <title>安全公告看上去是什么样子？</title>

      <para>&os; 安全公告的样式类似下面的范例， 这一例子来自
	&a.security-notifications.name; 邮件列表。</para>

      <programlisting>=============================================================================
&os;-SA-XX:XX.UTIL                                     Security Advisory
                                                          The &os; Project

Topic:          denial of service due to some problem<co id="co-topic">

Category:       core<co id="co-category">
Module:         sys<co id="co-module">
Announced:      2003-09-23<co id="co-announce">
Credits:        Person@EMAIL-ADDRESS<co id="co-credit">
Affects:        All releases of &os;<co id="co-affects">
                &os; 4-STABLE prior to the correction date
Corrected:      2003-09-23 16:42:59 UTC (RELENG_4, 4.9-PRERELEASE)
                2003-09-23 20:08:42 UTC (RELENG_5_1, 5.1-RELEASE-p6)
                2003-09-23 20:07:06 UTC (RELENG_5_0, 5.0-RELEASE-p15)
                2003-09-23 16:44:58 UTC (RELENG_4_8, 4.8-RELEASE-p8)
                2003-09-23 16:47:34 UTC (RELENG_4_7, 4.7-RELEASE-p18)
                2003-09-23 16:49:46 UTC (RELENG_4_6, 4.6-RELEASE-p21)
                2003-09-23 16:51:24 UTC (RELENG_4_5, 4.5-RELEASE-p33)
                2003-09-23 16:52:45 UTC (RELENG_4_4, 4.4-RELEASE-p43)
                2003-09-23 16:54:39 UTC (RELENG_4_3, 4.3-RELEASE-p39)<co id="co-corrected">
&os; only:   NO<co id="co-only">

For general information regarding FreeBSD Security Advisories,
including descriptions of the fields above, security branches, and the
following sections, please visit
http://www.FreeBSD.org/security/.

I.   Background<co id="co-backround">


II.  Problem Description<co id="co-descript">


III. Impact<co id="co-impact">


IV.  Workaround<co id="co-workaround">


V.   Solution<co id="co-solution">


VI.  Correction details<co id="co-details">


VII. References<co id="co-ref"></programlisting>


      <calloutlist>
	<callout arearefs="co-topic">
	  <para><literal>Topic</literal>(标题) 一栏说明了问题到底是什么。
	    它基本上是对所发现的安全问题及其所涉及的工具的描述。</para>
	</callout>

	<callout arearefs="co-category">
	  <para><literal>Category</literal> (分类) 是指系统中受到影响的组建，
	    这一栏可能是 <literal>core</literal>、 <literal>contrib</literal>，
	    或者 <literal>ports</literal> 之一。 <literal>core</literal>
	    分类表示安全弱点影响到了 &os; 操作系统的某个核心组件。
	    <literal>contrib</literal> 分类表示弱点存在于某个捐赠给
	    &os; Project 的软件， 例如
	    <application>sendmail</application>。
	    最后是 <literal>ports</literal>， 它表示该弱点影响了 Ports
	    Collection 中的某个第三方软件。</para>
	</callout>

	<callout arearefs="co-module">
	  <para><literal>Module</literal>(模块) 一栏给出了组件的具体位置，
	    例如 <literal>sys</literal>。 在这个例子中， 可以看到
	    <literal>sys</literal> 模块是存在问题的； 因此，
	    这个漏洞会影响某个在内核中的组件。</para>
	</callout>

	<callout arearefs="co-announce">
	  <para><literal>Announced</literal>(发布时间) 一栏反映了与安全公告有关的数据是什么时候公之于众的。
	    这说明安全团队已经证实问题确实存在， 而补丁已经写入了 &os;
	    的代码库。</para>
	</callout>

	<callout arearefs="co-credit">
	  <para><literal>Credits</literal>(作者) 一栏给出了注意到问题存在并报告它的个人或团体。</para>
	</callout>

	<callout arearefs="co-affects">
	  <para>The <literal>Affects</literal>(影响范围) 一栏给出了 &os; 的那些版本存在这个漏洞。
	    对于内核来说， 检视受影响的文件上执行的 <command>ident</command> 输出可以帮助确认文件版本。
	    对于 ports， 版本号在 <filename>/var/db/pkg</filename> 里面的 port 的名字后面列出。
	    如果系统没有与 &os; <acronym>CVS</acronym> 代码库同步并每日构建，
	    它很可能是有问题的。</para>
	</callout>

	<callout arearefs="co-corrected">
	  <para><literal>Corrected</literal>(修正时间) 一栏给出了发行版本中修正问题的具体日期、时间和时差。</para>
	</callout>

	<callout arearefs="co-only">
	  <para><literal>&os; only</literal>(仅 &os;) 一栏说明了漏洞是否只影响
	    &os;， 还是也影响一些其它操作系统。</para>
	</callout>

	<callout arearefs="co-backround">
	  <para><literal>Background</literal>(技术背景) 一栏提供了受影响的组件的作用。
	    多数时候这一部分会说明为什么 &os; 中包含了它， 它的作用， 以及它的一些原理。</para>
	</callout>

	<callout arearefs="co-descript">
	  <para><literal>Problem Description</literal>(问题描述) 一栏深入阐述安全漏洞的技术细节。
	    这部分有时会包括有问题的代码相关的详细情况，
	    甚至是这个部件如何能够被恶意利用并打开漏洞的细节。</para>
	</callout>

	<callout arearefs="co-impact">
	  <para><literal>Impact</literal>(影响) 一栏描述了问题能够造成的影响类型。
	    例如， 可能导致拒绝服务攻击， 权限提升， 甚至导致得到超级用户的权限。</para>
	</callout>

	<callout arearefs="co-workaround">
	  <para><literal>Workaround</literal>(应急方案) 一栏给出了系统管理员在暂时无法升级系统时可以采取的临时性对策。
	    这些原因可能包括时间限制， 网络资源的限制， 或其它因素。
	    不过无论如何， 安全不能够被轻视， 有问题的系统要么应该打补丁，
	    要么应该实施这种应急方案。</para>
	</callout>

	<callout arearefs="co-solution">
	  <para><literal>Solution</literal>(解决方案) 一栏提供了如何给有问题的系统打补丁的方法。
	    这是经过逐步测试和验证过的给系统打补丁并让其安全地工作的方法。</para>
	</callout>

	<callout arearefs="co-details">
	  <para>=<literal>Correction Details</literal>(修正细节) 一栏展示了针对
	    <acronym>CVS</acronym> 分支或某个发行版的修正特征。
	    同时也提供了每个分支上相关文件的版本号。</para>
	</callout>

	<callout arearefs="co-ref">
	  <para><literal>References</literal>(文献) 一栏通常会给出其它信息的来源。
	    这可能包括 <acronym>URL</acronym>， 书籍、 邮件列表以及新闻组。</para>
	</callout>
      </calloutlist>
    </sect2>
  </sect1>

  <sect1 id="security-accounting">
    <sect1info>
      <authorgroup>
	<author>
	  <firstname>Tom</firstname>
	  <surname>Rhodes</surname>
	  <contrib>Contributed by </contrib>
	</author>
      </authorgroup>
    </sect1info>
    <indexterm>
      <primary>进程记帐</primary>
    </indexterm>
    <title>进程记帐</title>

    <para>进程记帐是一种管理员可以使用的跟踪系统资源使用情况的手段，
      包括它们分配给了哪些用户、 提供系统监视手段，
      并且可以精细到用户执行的每一个命令。</para>

    <para>当然， 这种做法是兼有利弊的。 它的好处是，
      查找入侵时可以迅速把范围缩小到攻击者进入的时刻；
      而这样做的缺点， 则是记帐会产生大量的日志，
      因而需要很多磁盘空间来存储它们。
      这一节将带领管理员一步一步地配置基本的进程记帐。</para>

    <sect2>
      <title>启用并利用进程记帐</title>
      <para>在使用进程记帐之前， 管理员必须启用它。
	要完成这项工作， 需要运行下面的命令：</para>

      <screen>&prompt.root; <userinput>touch <filename>/var/account/acct</filename></userinput>

&prompt.root; <userinput>accton <filename>/var/account/acct</filename></userinput>

&prompt.root; <userinput>echo 'accounting_enable="YES"' &gt;&gt; <filename>/etc/rc.conf</filename></userinput></screen>

      <para>一旦启用之后， 记帐就会开始跟踪
	<acronym>CPU</acronym> 统计数据、 命令， 等等。
	所有的记帐日志不是以可读的方式记录的， 要查看它们，
	需要使用 &man.sa.8; 这个工具。 如果没有给出其他参数， 则
	<command>sa</command> 将按用户， 以分钟为单位显示他们所使用的时间、
	总共的 <acronym>CPU</acronym> 和用户时间，
	以及平均的 I/O 操作数目， 等等。</para>

      <para>要显示关于刚刚发出的命令的相关信息，
	则应使用 &man.lastcomm.1; 工具。
	<command>lastcomm</command> 可以用来显示在某一 &man.ttys.5;
	上的用户信息， 例如：</para>

      <screen>&prompt.root; <userinput>lastcomm ls
	<username>trhodes</username> ttyp1</userinput></screen>

      <para>将会显示出所有已知的 <username>trhodes</username>
        在 ttyp1 终端上执行 <command>ls</command> 的情况。</para>

      <para>更多的可用选项在联机手册
	&man.lastcomm.1;、 &man.acct.5; 和 &man.sa.8; 中有所介绍。</para>
    </sect2>
  </sect1>  
</chapter>

<!--
     Local Variables:
     mode: sgml
     sgml-declaration: "../chapter.decl"
     sgml-indent-data: t
     sgml-omittag: nil
     sgml-always-quote-attributes: t
     sgml-parent-document: ("../book.sgml" "part" "chapter")
     End:
-->
