如何向 Linux 内核提交驱动

当Linux驱动程序开发到一定阶段,向kernel.org提交代码是一个很好的选择。对于很多没有向上游提交过代码的开发者来说,还是有很多疑问需要解决的。比如,究竟我们向哪里提交驱动程序?提交时我们的代码应该处于什么状态?提交的过程又如何呢?

如何向 Linux 内核提交驱动
如何向 Linux 内核提交驱动

向哪里提交

Linux staging tree是Greg KH建立的用于提交驱动程序的git仓库。我们可以把staging tree看作是代码进入mainline内核之前的一个预科班,新增的驱动程序首先需要放到这里供社区review和测试。Staging tree是 Greg KH于2008年建立的一棵kernel tree,其建立之目的是用来放置一些未充分测试或者因为一些其他原因未能进入内核的新增驱动程序和新增文件系统。

Linux staging tree的URL是” git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging-2.6.git “或者” http://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging-2.6.git “。这里需要注意的是,git协议的端口号是9418,因为很多公司的防火墙只会开放80端口,clone代码仓库时如果git协议超时,不妨试试http协议。

关于Linux staging tree更详细的描述可以参考我前一篇博文《小议Linux staging tree》。

我们的代码

在我们向上游提交驱动程序之前,需要保证代码能够遵循Linux内核的coding style。当然,这个规定并不是强制的,如果您经常阅读Linux内核代码,就会发现很多驱动对内核coding style的遵循情况也并不是太好。但一致的代码风格对代码的维护大有裨益,所以对作为Linux内核驱动程序员的我们来说,遵循coding style是一个很好的习惯。关于Linux内核的coding style的详细信息,可以参考Linux内核里的Documentation/CodingStyle文档,或者我之前的博文《谈谈为 Linux 内核开发驱动代码的编码风格》。

我们在提交驱动之前还需要用静态代码检查工具sparse来检查一下代码。

sparse的源代码可以从“git://git.kernel.org/pub/scm/devel/sparse/sparse.git”获得,得到代码之后,执行”make; make install”来编译生成可执行程序。默认情况下,sparse程序会被放到目录“~/bin”下面,如果您不喜欢这个位置,可以修改Makefile来设定路径。需要注意的是,使用sparse之前,PATH环境变量要设置正确。

sparse的使用方法很简单,只要在make驱动程序时加上“C=N”的选项即可,其中N的取值是1或者2。当N=1时表示对需要重新编译的C文件进行代码检查,N=2时表示对所有的C文件进行代码检查。

对于staging目录下的驱动来说,我们还需要附上一个TODO文件,用来描述未来的维护计划。一般情况下,TODO文件可以这样写:

TODO:
- support more features
- use kernel coding style
- checkpatch.pl fixes

如何提交

我们可以通过patch的形式把驱动程序提交给staging tree。提交之前,需要首先把staging tree clone到本地,然后基于当前的工作目录制作patch。

Git提供了制作格式化的patch的功能,命令如下:

git format-patch -N

其中,N是整数,用来指定我们把最近N次提交做成N个patch。比如当N=1时,就表示把最近一次提交制作成patch。Git会根据提交的log信息来自动命名patch文件。

这里需要注意的是,每次提交的log的描述要遵循一定的格式。

Log的第一行是一个简短的描述。本文主要介绍如何向staging tree提交代码,我们需要在Log首行以“staging:”开头。Log的最后一行需要提供提交者的email信息,我们可以这样写:“Signed-off-by: wwang ”。

举个例子,假定我们的staging driver命名为hello_world,log的格式可以参考如下:

staging: hello_world: My first commit
This is my first commit.
Signed-off-by: wwang 

Patch生成之后,我们需要把它寄给staging tree的维护者,通常是Greg KH本人以及linux内核驱动的开发者列表。这个步骤也可以使用git来帮助我们完成,但首先需要确定系统里已经安装msmtp和git-email这两个包。这里还需提醒一下,如果您的邮件服务器是Exchange,很可能需要NTLM认证,这就要求msmtp支持NTLM。Ubuntu仓库里的msmtp默认支持NTLM,可以直接使用,但还有些其他的发行版的软件仓库里自带的msmtp并不支持NTLM(如Arch Linux),这种情况就需要自己编译了。

msmtp安装好之后,需要配置”~/.msmtprc”文件。以Gmail为例,”.msmtprc”可以这样配置:

# Set default values for all following accounts.
defaults
logfile ~/.msmtp.log

# gmail
account gmail
protocol smtp
host smtp.gmail.com
from my@gmail.com
user my@gmail.com
password mypasswd
port 587
auth on
tls on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
syslog LOG_MAIL

# Set a default account
account default : gmail

用git发送patch的命令如下:

git send-email
  --smtp-server /usr/bin/msmtp
  --from my@gmail.com
  --to gregkh@suse.de
  --to devel@linuxdriverproject.org
  --to linux-kernel@vger.kernel.org
  ./my.patch

将patch发送出去只是提交驱动程序的第一步,之后还需要不断的维护与完善,把代码丢给内核然后就放手不管的做法是不可取的。提交代码还有一个原则,就是每次提交只做一件事情,这样才会比较方便内核维护者来review我们的代码。

来源:http://www.cnblogs.com/wwang/archive/2011/04/01/1951742.html

Linux:25 个有用 Apache ‘.htaccess’ 技巧

网站是我们生活中重要的一部分。它们是实现扩大业务、分享知识以及其它更多功能的方式。早期受制于只能提供静态内容,随着动态客户端和服务器端脚本语言的引入和现有静态语言的持续改进,例如从 html 到 html5,动态网站成为可能,剩下的也许在不久的将来也会实现。

对于网站,随之而来的是需要一个能向全球大规模用户显示站点的某个东西。这个需求可以通过托管网站的服务器实现。这包括一系列的服务器,例如:Apache HTTP Server、Joomla 以及 允许个人拥有自己网站的 WordPress。

Linux:25 个有用 Apache ‘.htaccess’ 技巧
Linux:25 个有用 Apache ‘.htaccess’ 技巧

25 个 htaccess 小技巧

想要拥有一个网站,可以创建一个自己的本地服务器,或者联系任何上面提到的或其它服务器管理员来托管他的网站。但实际问题也从这点开始。网站的性能主要取决于以下因素:

  • 网站消耗的带宽。
  • 面对黑客,网站有多安全。
  • 对数据库进行数据检索时的优化。
  • 显示导航菜单和提供更多 UI 功能时的用户友好性。

除此之外,保证托管网站服务器成功的多种因素还包括:

  • 对于一个流行站点的数据压缩量。
  • 同时为多个对请求同一或不同站点的用户服务的能力。
  • 保证网站上输入的机密数据安全,例如:Email、信用卡信息等等。
  • 允许更多的选项用于增强站点的动态性。

这篇文章讨论一个服务器提供的用于增强网站性能和提高针对坏机器人、热链等的安全性的功能:‘.htaccess’ 文件。

.htaccess 是什么?

htaccess (hypertext access,超文本访问) 是为网站所有者提供用于控制服务器环境变量以及其它参数的选项,从而增强他们网站的功能的文件。这些文件可以在网站目录树的任何一个目录中,并向该目录以及目录中的文件和子目录提供功能。

这些功能是什么呢?其实这些是服务器的指令,例如命令服务器执行特定任务的行,这些命令只对该文件所在目录中的文件和子目录有效。这些文件默认是隐藏的,因为所有操作系统和网站服务器默认配置为忽略它们,但如果查看隐藏文件的话,你就可以看到这些特殊文件。后续章节的话题将讨论能控制什么类型的参数。

注意:如果 .htaccess 文件保存在 /apache/home/www/Gunjit/ 目录,那么它会向该目录中的所有文件和子目录提供命令,但如果该目录包含一个名为 /Gunjit/images/ 子目录,且该子目录中也有一个 .htaccess 文件,那么这个子目录中的命令会覆盖父目录中 .htaccess 文件(或者目录层次结构中更上层的文件)提供的命令。

Apache Server 和 .htaccess 文件

Apache HTTP Server 俗称为 Apache,是为了表示对一个有卓越战争策略技能的美洲土著部落的尊敬而命名。它基于 NCSA HTTPd 服务器 ,是用 C/C++ 和 XML 建立的跨平台 Web 服务器,它在万维网的成长和发展中起到了关键作用。

它最常用于 UNIX,但 Apache 也能用于多种平台,包括 FreeBSD、Linux、Windows、Mac OS、Novel Netware 等。在 2009 年,Apache 成为第一个为超过一亿站点提供服务的服务器。

Apache 服务器可以让 www/ 目录中的每个用户有一个单独的 .htaccess 文件。尽管这些文件是隐藏的,但如果需要的话可以使它们可见。在 www/ 目录中可以有很多子目录,每个子目录通过用户名或所有者名称命名,包含了一个站点。除此之外你可以在每个子目录中有一个 .htaccess 文件,像之前所述用于配置子目录中的文件。

下面介绍如果配置 Apache 服务器上的 htaccess 文件。

Apache 服务器上的配置

这里有两种情况:

在自己的服务器上托管网站

在这种情况下,如果没有启用 .htaccess 文件,你可以通过在 http.conf(Apache HTTP 守护进程的默认配置文件) 中找到 部分启用。


定位如下行

AllowOverride None

更改为

AllowOverride All

现在,重启 Apache 后就启用了 .htaccess。

在不同的托管服务提供商的服务器上托管网站

在这种情况下最好咨询托管管理员,如果他们允许访问 .htaccess 文件的话。

用于网站的 25 个 Apache Web 服务器 ‘.htaccess’ 小技巧

1. 如何在 .htaccess 文件中启用 mod_rewrite

mod_rewrite 选项允许你使用重定向并通过重定向到其它 URL 来隐藏你真实的 URL。这个选项非常有用,允许你用短的容易记忆的 URL 替换长 URL。

要允许 mod_rewrite,只需要在你的 .htaccess 文件的第一行添加如下一行。

Options +FollowSymLinks

该选项允许你跟踪符号链接从而在站点中启用 modrewrite。后面会介绍用短 URL 替换。(LCTT 译注:+FollowSymLinks 只是启用 modrewrite 的前提之一,还需要在全局和虚拟机中设置 RewriteEngine on才能启用重写模块。)

2. 如何允许或禁止对站点的访问

通过使用 order、allow 和 deny 关键字,htaccess 文件可以允许或者禁止对站点或目录中子目录或文件的访问。

只允许 IP 192.168.3.1 的访问

Order Allow, Deny
Deny from All
Allow from 192.168.3.1

或

Order Allow, Deny
Allow from 192.168.3.1

这里的 Order 关键字指定处理 allow 和 deny 访问的顺序。对于上面的 ‘Order’ 语句,首先会处理 Allow 语句,然后是 deny 语句。

只禁止某个 IP 的访问

下面一行的意思是除了 IP 地址 192.168.3.1,允许所有用户访问网站。

Order Allow, Deny
Deny from 192.168.3.1
Allow from All

或

Order Deny, Allow
Deny from 192.168.3.1

3. 为不同错误码生成 Apache 错误文档

用简单几行,我们可以解决当用户/客户端请求一个站点上不可用的网页时服务器产生的错误码的错误文档,例如我们大部分人见过的浏览器中显示的 ‘404 Page not found’。‘.htaccess’ 文件指定了发生这些错误情况时采取何种操作。

要做到这点,需要添加下面的行到 ‘.htaccess’ 文件:

ErrorDocument  

‘ErrorDocument’ 是一个关键字,error-code 可以是 401、403、404、500 或任何有效的表示错误的代码,最后 ‘path-of-document’ 表示本地机器上的路径(如果你使用的是你自己的本地服务器) 或服务器上的路径(如果你使用任何其它服务器来托管网站)。

例子:

ErrorDocument 404 /error-docs/error-404.html

上面一行设置客户请求任何无效页面,服务器报告 404 错误时显示 error-docs 目录下的 ‘error-404.html’ 文档。

404 Page not found

The page you request is not present. Check the URL you have typed

 

上面的表示也正确,其中字符串相当于一个普通的 html 文件。

4. 设置/取消 Apache 服务器环境变量

在 .htaccess 文件中你可以设置或者取消站点所有者可以更改的全局环境变量。要设置或取消环境变量,你需要在你的 .htaccess 文件中添加下面的行。

设置环境变量

SetEnv OWNER “Gunjit Khera”

取消环境变量

UnsetEnv OWNER

5. 为文件定义不同 MIME 类型

MIME(多用途 Internet 多媒体扩展)是浏览器运行任何页面所默认识别的类型。你可以在 .htaccess 文件中为你的站点定义 MIME 类型,然后服务器就可以识别你定义类型的文件并运行。


    AddType application/javascript      js
    AddType application/x-font-ttf      ttf ttc

这里,mod_mime.c 是用于控制定义不同 MIME 类型的模块,如果在你的系统中已经安装了这个模块,那么你就可以用该模块去为你站点中不同的扩展名定义不同的 MIME 类型,从而让服务器可以理解这些文件。

6. 如何在 Apache 中限制上传和下载的大小

.htaccess 文件允许你能够控制某个用户从你的站点(通过 PHP)单次上传数据量的大小(LCTT 译注:原文有误,修改)。要做到这点你只需要添加下面的行到你的 .htaccess 文件:

php_value upload_max_filesize 20M
php_value post_max_size 20M
php_value max_execution_time 200
php_value max_input_time 200

上面的行设置最大上传大小、最大POST 提交数据大小、最长执行时间(例如,允许用户在他的本地机器上单次执行一个请求的最大时间)、限制的最大输入时间。

7. 让用户不能在你的站点上在线播放 .mp3 和其它文件

大部分情况下,人们在下载检查音乐质量之前会在网站上播放等等。作为一个聪明的销售者,你可以添加一个简单的功能,不允许任何用户在线播放音乐或视频,而是必须下载完成后才能播放。这非常有用,因为(无缓冲的)在线播放音乐和视频会消耗很多带宽。

要添加下面的行到你的 .htaccess 文件:

AddType application/octet-stream .mp3 .zip

8. 为站点设置目录索引

大部分网站开发者都知道第一个显示的页面是哪个,例如一个站点的首页,被命名为 ‘index.html’。我们大部分也见过这个。但是如何设置呢?

.htaccess 文件提供了一种方式用于列出一个客户端请求访问网站的主页面时会顺序扫描的一些网页集合,相应地如果找到了列出的页面中的任何一个就会作为站点的主页面并显示给用户。

需要添加下面的行产生所需的效果。

DirectoryIndex index.html index.php yourpage.php

上面一行指定如果有任何访问首页的请求到来,首先会在目录中顺序搜索上面列出的网页:如果发现了 index.html 则显示为主页面,否则会找下一个页面,例如 index.php,如此直到你在列表中输入的最后一个页面。

9. 如何为文件启用 GZip 压缩以节省网站带宽

繁忙的站点通常比只占少量空间的轻量级站点运行更慢,这是常见的现象。因为对于繁忙的站点需要时间加载巨大的脚本文件和图片以在客户端的 Web 浏览器上显示。

通常的机制是这样的,当浏览器请求一个 web 页面时,服务器提供给浏览器该页面,并在浏览器端显示该 web 页面,浏览器需要下载该页面并运行页面内的脚本。

这里 GZip 压缩所做的就是节省单个用户的服务时间而不用增加带宽。服务器上站点的源文件以压缩形式保存,当用户请求到来的时候,这些文件以压缩形式传送,然后在客户端上解压(LCTT 译注:原文此处有误)。这改善了带宽限制。

下面的行允许你压缩站点的源文件,但要求在你的服务器上安装 mod_deflate.c 模块。


    AddOutputFilterByType DEFLATE text/plain
    AddOutputFilterByType DEFLATE text/html
    AddOutputFilterByType DEFLATE text/xml
    AddOutputFilterByType DEFLATE application/html
    AddOutputFilterByType DEFLATE application/javascript
    AddOutputFilterByType DEFLATE application/x-javascript

10. 处理文件类型

服务器默认的有一些特定情况。例如:在服务器上运行 .php 文件,显示 .txt 文件。像这些我们可以以源代码形式只显示一些可执行 cgi 脚本或文件而不是执行它们(LCTT 译注:这是为了避免攻击者通过上传恶意脚本,进而在服务器上执行恶意脚本进行破坏和窃取)。

要做到这点在 .htaccess 文件中有如下行。

RemoveHandler cgi-script .php .pl .py
AddType text/plain .php .pl .py

这些行告诉服务器只显示而不执行 .pl (perl 脚本)、.php (PHP 文件) 和 .py (Python 文件) 。

11. 为 Apache 服务器设置时区

从 .htaccess 文件可用于为服务器设置时区可以看出它的能力和重要性。这可以通过设置一个服务器为每个托管站点提供的一系列全局环境变量中的 ‘TZ’ 完成。

由于这个原因,我们可以在网站上看到根据我们的时区显示的时间。也许服务器上其他拥有网站的人会根据他居住地点的位置设置时区。

下面的一行为服务器设置时区。

SetEnv TZ India/Kolkata

12. 如果在站点上启用缓存控制

浏览器很有趣的一个功能是,很多时间你可以看到,当多次同时打开一个网站和第一次打开相比前者会更快。但为什么会这样呢?事实上,浏览器在它的缓存中保存了一些通常访问的页面用于加快后面的访问。

但保存多长时间呢?这取决于你自己。例如,你的 .htaccess 文件中设置的缓存控制时间。.htaccess 文件指定了站点的网页可以在浏览器缓存中保存的时间,时间到期后需要重新验证缓存,页面可能会从缓存中删除然后在下次用户访问站点的时候重建。

下面的行为你的站点实现缓存控制。


    Header Set Cache-Control "max-age=3600, public"


    Header Set Cache-Control "public"
    Header Set Expires "Sat, 24 Jan 2015 16:00:00 GMT"

上面的行允许缓存 .htaccess 文件所在目录中的页面一小时。

13. 配置单个文件

通常 .htaccess 文件中的内容会对该文件所在目录中的所有文件和子目录起作用,但是你也可以对特殊文件设置一些特殊权限,例如只禁止对某个文件的访问等等。

要做到这点,你需要在文件中以类似方式添加 标记:


Order allow, deny
Deny from 188.100.100.0

这是一个禁止 IP 188.100.100.0 访问 ‘conf.html’ 的简单例子,但是你也可以添加介绍过的 .htaccess 文件的任何功能,包括将要介绍的功能,例如:缓存控制、GZip 压缩。

大部分服务器会用这个功能增强 .htaccess 文件的安全,这也是我们在浏览器上看不到 .htaccess 文件的原因。在后面的章节中会介绍如何给文件授权。

14. 启用在 cgi-bin 目录以外运行 CGI 脚本

通常服务器运行的 CGI 脚本都保存在 cgi-bin 目录中,但是你可以在你需要的目录运行 CGI 脚本,只需要在所需的目录中的 .htaccess 文件添加下面的行,如果没有该文件就创建一个,并添加下面的行:

AddHandler cgi-script .cgi
Options +ExecCGI

15.如何用 .htaccess 在站点上启用 SSI

服务器端包括(SSI)顾名思义是和服务器部分相关的东西。这是什么呢?通常当我们在站点上有很多页面的时候,我们在主页上会有一个显示到其它页面链接的导航菜单,我们可以启用 SSI 选项允许导航菜单中显示的所有页面完全包含在主页面中。

SSI 允许多个页面包含同样的内容,因此只需要编辑一个文件就行,从而可以节省很多磁盘空间。对于 .shtml 文件,服务器默认启用了该选项。

如果你想要对 .html 启用该选项,你需要添加下面的行:

AddHandler server-parsed .html

这样 html 文件中如下部分会被替换为 SSI。


16. 如何防止网站列出目录列表

为防止任何客户端在本地机器罗列服务器上的网站目录列表,添加下面的行到你不想列出的目录的文件中。

Options -Indexes

17. 更改默认字符集和语言头

.htaccess 文件允许你更改网站使用的字符集,例如 ASCII 或 UNICODE,UTF-8 等,以及用于显示内容的默认语言。

在服务器的全局环境变量之后添加下面语句可以实现上述功能。

AddDefaultCharset UTF-8
DefaultLanguage en-US

18. 重定向一个非 www URL 到 www URL

在开始解释之前,首先看看如何启用该功能,添加下列行到 .htaccess 文件。

RewriteEngine ON
RewriteCond %{HTTP_HOST} ^abc.net$
RewriteRule (.*) http://www.abc.net/$1 [R=301,L]

上面的行启用重写引擎,然后在第二行检查所有涉及到主机 abc.net 或 环境变量 HTTP_HOST 为 “abc.net” 的 URL。

对于所有这样的 URL,代码永久重定向它们(如果启用了 R=301 规则)到新 URL http://www.abc.net/$1,其中 $1 是主机为 abc.net 的非 www URL。非 www URL 是大括号内的内容,并通过 $1 引用。

重写 URL 的重定向规则

重写功能简单的说,就是用短而易记的 URL 替换长而难以记忆的 URL。但是,在开始这个话题之前,这里有一些本文后面会使用的特殊字符的规则和约定。

特殊符号:

符号              含义
^         -     字符串开头
$         -     字符串结尾
|         -     或 [a|b] : a 或 b
[a-z]     -     a 到 z 的任意字母
+         -     之前字母的一次或多次出现
*         -     之前字母的零次或多次出现
?         -     之前字母的零次或一次出现

常量和它们的含义:

常量          含义
NC          -   区分大小写
L           -   最后的规则 – 停止处理后面规则
R           -   临时重定向到新 URL
R=301       -   永久重定向到新 URL
F           -   禁止发送 403 头给用户
P           -   代理 - 获取远程内容代替部分并返回
G           -   Gone, 不再存在
S=x         -   跳过后面的 x 条规则
T=mime-type -   强制指定 MIME 类型
E=var:value -   设置环境变量 var 的值为 value
H=handler   -   设置处理器
PT          -   Pass through - 用于 URL 还有额外的头
QSA         -   将查询字符串追加到替换 URL

19. 重定向整个站点到 https

下面的行会帮助你转换整个网站到 https:

RewriteEngine ON
RewriteCond %{HTTPS} !on
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}

上面的行启用重写引擎,然后检查环境变量 HTTPS 的值。如果设置了那么重写所有网站页面到 https。

20.一个自定义重写例子

例如,重定向 url ‘http://www.abc.net?p=100&q=20’ 到 ‘http://www.abc.net/10020pq’。

RewriteEngine ON
RewriteRule ^http://www.abc.net/([0-9]+)([0-9]+)pq$ ^http://www.abc.net?p=$1&q=$2

在上面的行中,$1 表示第一个括号,$2 表示第二个括号。

21. 重命名 htaccess 文件

为了防止入侵者和其他人查看 .htaccess 文件,你可以重命名该文件,这样就不能通过客户端浏览器访问。实现该目标的语句是:

AccessFileName  htac.cess

22. 如何为你的网站禁用图片盗链

网站带宽消耗比较大的另外一个重要问题是盗链问题,这是其它站点用于显示你网站的图片而链接到你的网站的链接,这会消耗你的带宽。这问题也被成为 ‘带宽盗窃’。

一个常见现象是当一个网站要显示其它网站所包含的图片时,由于该链接需要从你的网站加载内容,消耗你站点的带宽而为其它站点显示图片。为了防止出现这种情况,比如对于 .gif、.jpeg 图片等,下面的代码行会有所帮助:

RewriteEngine ON
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERERER} !^http://(www.)?mydomain.com/.*$ [NC]
RewriteRule .(gif|jpeg|png)$ - [F].

上面的行检查 HTTP_REFERER 是否没有设为空或没有设为你站点上的任何链接。如果是这样的话,你网页上的所有图片会用 403 禁止访问代替。

23. 如何将用户重定向到维护页面

如果你的网站需要进行维护并且你想向所有需要访问该网站的你的所有客户通知这个消息,对于这种情况,你可以添加下面的行到你的 .htaccess 文件,从而只允许管理员访问并替换所有访问 .jpg、.css、.gif、.js 等的页面内容。

RewriteCond %{REQUEST_URI} !^/admin/ [NC]
RewriteCond %{REQUEST_URI} !^((.*).css|(.*).js|(.*).png|(.*).jpg)    [NC]
RewriteRule ^(.*)$ /ErrorDocs/Maintainence_Page.html [NC,L,U,QSA]

这些行检查请求 URL 是否包含任何例如以 ‘/admin/’ 开头的管理页面的请求,或任何到 ‘.png, .jpg, .js, .css’ 页面的请求,对于任何这样的请求,用 ‘ErrorDocs/Maintainence_Page.html’ 替换那个页面。

24. 映射 IP 地址到域名

名称服务器是将特定 IP 地址转换为域名的服务器。这种映射也可以在 .htaccess 文件中用以下形式指定。

# 为了将IP地址 L.M.N.O 映射到域名 www.hellovisit.com
RewriteCond %{HTTP_HOST} ^L.M.N.O$ [NC]
RewriteRule ^(.*)$ http://www.hellovisit.com/$1 [L,R=301]

上面的行检查任何页面的主机是否包含类似 L.M.N.O 的 IP 地址,如果是的话第三行会通过永久重定向将页面映射到域名 http://www.hellovisit.com。

25. FilesMatch 标签

类似用于应用条件到单个文件的 标签, 能用于匹配一组文件并对该组文件应用一些条件,如下:


Order Allow, Deny
Deny from All

结论

.htaccess 文件能实现的小技巧还有很多。这告诉了我们这个文件有多么强大,通过该文件能给你的站点添加多少安全性、动态性以及其它功能。

我们已经在这篇文章中尽最大努力覆盖尽可能多的 htaccess 小技巧,但如果我们缺少了任何重要的技巧,或者你愿意告诉我们你的 htaccess 想法和技巧,你可以在下面的评论框中提交,我们也会在文章中进行介绍。


via: http://www.tecmint.com/apache-htaccess-tricks/

作者:Gunjit Khera 译者:ictlyh 校对:wxy

本文由 LCTT 原创翻译,Linux中国 荣誉推出

来源:https://linux.cn/article-5731-1.html

Linux:纯手工玩转 Nginx 日志

Nginx 日志对于大部分人来说是个未被发掘的宝藏,总结之前做某日志分析系统的经验,和大家分享一下 Nginx 日志的纯手工分析方式。

Linux:纯手工玩转 Nginx 日志
Linux:纯手工玩转 Nginx 日志

Nginx 日志相关配置有 2 个地方:access_log 和 log_format 。

默认的格式:

access_log /data/logs/nginx-access.log;

log_format old '$remote_addr [$time_local] $status $request_time $body_bytes_sent '
    '"$request" "$http_referer" "$http_user_agent"';

相信大部分用过 Nginx 的人对默认 Nginx 日志格式配置都很熟悉,对日志的内容也很熟悉。但是默认配置和格式虽然可读,但是难以计算。

Nginx 日志刷盘相关策略可配置:

比如,设置 buffer,buffer 满 32k 才刷盘;假如 buffer 不满 5s 钟强制刷盘的配置如下:

access_log /data/logs/nginx-access.log buffer=32k flush=5s;

这决定了是否实时看到日志以及日志对磁盘 IO 的影响。

Nginx 日志能够记录的变量还有很多没出现在默认配置中:

比如:

  • 请求数据大小:$request_length
  • 返回数据大小:$bytes_sent
  • 请求耗时:$request_time
  • 所用连接序号:$connection
  • 当前连接发生请求数:$connection_requests

Nginx 的默认格式不可计算,需要想办法转换成可计算格式,比如用控制字符 ^A (Mac 下 ctrl+v ctrl+a 打出)分割每个字段。

log_format 的格式可以变成这样:

log_format new '$remote_addr^A$http_x_forwarded_for^A$host^A$time_local^A$status^A'
    '$request_time^A$request_length^A$bytes_sent^A$http_referer^A$request^A$http_user_agent';

这样之后就通过常见的 Linux 命令行工具进行分析了:

  • 查找访问频率最高的 URL 和次数:
    cat access.log | awk -F ‘^A’ ‘{print $10}’ | sort | uniq -c
  • 查找当前日志文件 500 错误的访问:
    cat access.log | awk -F ‘^A’ ‘{if($5 == 500) print $0}’
  • 查找当前日志文件 500 错误的数量:
    cat access.log | awk -F ‘^A’ ‘{if($5 == 500) print $0}’ | wc -l
  • 查找某一分钟内 500 错误访问的数量:
    cat access.log | awk -F ‘^A’ ‘{if($5 == 500) print $0}’ | grep ’09:00’ | wc-l
  • 查找耗时超过 1s 的慢请求:
    tail -f access.log | awk -F ‘^A’ ‘{if($6>1) print $0}’
  • 假如只想查看某些位:
    tail -f access.log | awk -F ‘^A’ ‘{if($6>1) print $3″|”$4}’
  • 查找 502 错误最多的 URL:
    cat access.log | awk -F ‘^A’ ‘{if($5==502) print $11}’ | sort | uniq -c
  • 查找 200 空白页
    cat access.log | awk -F ‘^A’ ‘{if($5==200 && $8 < 100) print $3″|”$4″|”$11″|”$6}’
  • 查看实时日志数据流
    tail -f access.log | cat -e

    或者

    tail -f access.log | tr ‘^A’ ‘|’

总结

照着这个思路可以做很多其他分析,比如 UA 最多的访问;访问频率最高的 IP;请求耗时分析;请求返回包大小分析;等等。

这就是一个大型 Web 日志分析系统的原型,这样的格式也是非常方便进行后续大规模 batching 和 streaming 计算。

来源:http://blog.eood.cn/nginx_logs

Linux:如何在 Linux 平台下看蓝光影碟

随着蓝光光驱的价格逐步走低,这一未来高容量光存储介质也得到了更多人的认识。蓝光影碟更以它清晰的画面博得了电影发烧友的青睐。那么如何在 Linux 平台上欣赏蓝光影碟带来的视觉盛宴呢?

首先介绍下朝内市场上能见到的几种蓝光影碟:

  • 以 Blu-ray Ultra 为代表的 D 版蓝光,常见于各类音像店,单碟平均价格在 15~25 软妹币左右。此类蓝光影碟通过特殊软件从正版蓝光提取出来,除去了版权保护机制,然后写入 BD-R 载体。相比于以双层 DVD 为载体的 Real Blu-ray 伪蓝光而言,Blu-ray Ultra 的真正蓝光介质在一定程度上保证了有足够的容量放下未经二重压缩的视频和音轨。若是制品者不是太坑的话,原盘中的幕后花絮和交互式内容也可能保留。
  • 只有 AACS 加密的正版蓝光,仅见于海淘、音像店角落及收藏家手中,价格难以界定。属于早期蓝光制品,在 AACS 被爆掉之后就已经不在生产了。
  • 使用 BD+ 和 AACS 加密的正版蓝光,当下主要的正版蓝光影碟,见于各大电商和蓝光形象店,单碟平均价格在 50 ~ 100 左右。尽管朝内土地在蓝光分区时被归于 C 区,不过为了考虑到朝内复杂的蓝光回放设备来源,实际上不少在朝内正规渠道发行的蓝光影碟都是没有区域码的。不过相对在其他地区发行的版本,在附加内容上就有一些缩水了。 

下面以 Fedora 18 64bit 系统,先锋 BDC-207BK 蓝光康宝为例介绍如何在 Linux 下实现回放上面介绍的三种蓝光影碟。

在开始之前,请确保您的 Fedora 系统已经启用了 RPMFusion 仓库,并安装了 VLC Player:

pkcon install vlc

Blu-ray Ultra 蓝光影碟

VLC 从 2.0 开始已经可以理解蓝光影碟所用的 BDMV 和 BDAV 的结构,只是到目前为止蓝光交互式菜单的一直没有实现。于是对于不包含版权保护的 Blu-ray Ultra 是可以直接播放的。

如上图,在 VLC 文件菜单中选择打开光盘,格式选择为 Blu-ray,勾选上 “No discs menu” 即可。注意若忘记勾选后者的话可能会导致 VLC 崩溃哦~

仅使用 AACS 加密的蓝光影碟

播放仅包含 AACS 加密的蓝光影碟需要两个额外部分组件,一是公钥库文件,可以从这里下载(最后更新 2012 年 4 月 20 日),然后放置到 $HOME/.config/aacs/ 目录下即可。

另一个组件是 AACS 的开源实现动态链接库,可以从 rpmfusion 仓库里获得:

pkcon install libaacs

之后即可使用和打开 Blu-ray Ultra 同样的方式在 VLC 中播放仅有 AACS 加密的蓝光影碟了。

带有 BD+ 和 AACS 蓝光影碟

对于增添了 BD+ 保护的蓝光影碟情况则要复杂很多,要求一个可供 BD+ 虚拟机来运行版本验证程序,实现检查播放环境是否满足 HDCP 的安全播放要求的工作。目前来看只有来自GuinpinSoft 的 MakeMKV 可以比较完美的在 Linux 系统下模拟一个 BD+ 虚拟机并同时实现 AACS 解密。MakeMKV 是一款共享软件,其中 DVD 和 AVCHD 的流媒体及转码是免费的,对于蓝光则有 30 天体验的限制,在体验期过后需要购买价值 50 欧元的注册码。暂且将价格问题放到一边,先试试再说吧。

MakeMKV 由开源的设备驱动及图形界面,和闭源二进制的 BD+ 虚拟机实现等核心功能两部分组成。Linux 用户可以在官方论坛免费下载到这两部分,分别为 makemkv-oss 及 makemkv-bin。

接下来需要安装一些编译所依赖的软件包。官方论坛中列出了 Ubuntu 下的软件包,对于 Fedora 系统则可以使用如下命令安装:

pkcon install gcc-c++ glibc-devel openssl-devel expat-devel mesa-libGL-devel qt4-devel

然后分别解压之前的 makemkv-oss 和 makemkv-bin 压缩包,分别在各自的目录上执行以下命令,注意先从 makemkv-oss 开始 :

make -f makefile.linux

su -c ‘make -f makefile.linux install’

至此 MakeMKV 安装完成,剩下的操作就相当简单了。

  1. 在应用程序列表中找到 MakeMKV 并运行。
  2. 点击窗口中非常巨大的 “Open Blu-ray” 按钮开启蓝光影碟,大约十几秒之后即可看到蓝光影碟中的章节结构。
  3. 点击工具栏上的 Stream 按钮,请求 MakeMKV 创建以当前蓝光碟为内容的媒体服务器,媒体服务器的 URL 和端口号可以在下方的日志窗口中找到。
  4. 在本机的 VLC 或者同一局域网下的 VLC 中,选择“打开网络串流”,按照 URL:端口/stream/titleN.ts 的格式填入,其中 N 代表章节数字号,电影正片的章节号一般是 0 或者 1,通常是章节结构中占据空间最大的那个。
  5. 稍等后即可在 MakeMKV 窗口中看到客户端已连接的信息,同时显示光盘读取速度及播放缓存等信息。在 VLC 方面则和一般影片回放一样,亦可执行音轨切换和字幕切换等操作。

使用华纳在朝内正版发行的哈利波特蓝光全集测试,所有影片均可正常播放,中文字幕亦可调出。

此外还在 Xperia Z 上测试了 VLC for Android 远程回放,可以正常打开,但是受限于无线网络带宽,回放并不流畅。

具体截图稍后奉上。

除了可以将蓝光影碟架设成媒体服务器以外,MakeMKV 如同名字所示还支持从蓝光影碟生成 MKV 格式的文件,实现备份的功能。

MakeMKV 支持 Win32/64,Linux 32/64 及 OS X x86 以上操作系统,也是目前 OS X 和 Linux 系统下唯一能曲线实现正版蓝光影碟回放的方案。体验期之后 50 欧元的注册费用贵不贵,则由您自己考量咯~

总结

作为高清影片的指定光学载体,当下蓝光影碟在 Linux 系统上的回放远不及 DVD 那么成熟。MakeMKV 作为 OS X 和 Linux 下的唯一可行方案,仍有一定的上手难度,其偏高的注册授权费用,也是需要谨慎考虑的。

VIA http://www.linuxeden.com/html/softuse/20130405/137864.html

Linux:Cookies 的跨域脚本攻击 – Github 迁移域名的安全详解

上周五我们宣布并完成了把所有的GitHub页面迁移到新域名github.io。 这是个计划已久的行动,此举是为了防止恶意网站攻击和跨域cookie的漏洞,这些漏洞是通过在我们主站的子域名下控制客户内容产生的。

关于这些跨域攻击漏洞的可怕影响,大家可能会有一些困惑。我们希望这篇技术博客可以消除这些困惑。

一个二级域名传过来的Cookie

当你登陆GitHub.com时,我们通过响应的HTTP头部来设置session的cookie。这个cookie包含着唯一标识你的session数据:

Set-Cookie: _session=THIS_IS_A_SESSION_TOKEN; path=/; expires=Sun, 01-Jan-2023 00:00:00 GMT; secure; HttpOnly

这些GitHub发送给浏览器的session的cookie是设定在默认的域名上(github.com),这就意味着这些cookie是不能从二级域名*.github.com访问到的。而且我们也指定了HttpOnly属性,这意味着cookie也不能通过JavaScript 的API:document.cookie来读取。最后,我们指定了Secure属性,这意味着这些cookie只能通过HTTPS来传输。

因此,从GitHub托管网站读取或”窃取”session的cookie是不太可能的。通过在GitHub网站托管的用户代码是不容易获取到session的cookie,但由于浏览器通过HTTP请求来发送cookie,这种方式有可能把cookie从GitHub网站抛到GitHub父域名上。

当浏览器执行一个HTTP请求时,它通过header里单独的cookie发送一些和URL匹配的cookie,这些发送的cookie是以键-值对存在的。只有和请求的URL匹配的cookie才会发送出去,比如,当执行一个对github.com的请求时,设置在域名github.io上的cookie是不会发送的,但在github.com上的cookie将会发送。

GET / HTTP/1.1
Host: github.com
Cookie: logged_in=yes; _session=THIS_IS_A_SESSION_TOKEN;

Cookie抛出的问题是因为header中的cookie只包含了一系列键值对的cookie,并没有一些其他信息, 通过这些额外信息可以知道cookie设置在哪个域名上,比如路径或者域名。

最直接的跨域攻击涉及到:在GitHub托管网站页面,通过document.cookie这个JavaScript API设置一个_session的cookie。假设这个网站托管在*.github.com,那么这个cookie将会被设置到父域名的所有请求里,尽管事实是它只设置在了二级域名里。

/* set a cookie in the .github.com subdomain */
document.cookie = "_session=EVIL_SESSION_TOKEN; Path=/; Domain=.github.com"

 

GET / HTTP/1.1
Cookie: logged_in=yes; _session=EVIL_SESSION_TOKEN; _session=THIS_IS_A_SESSION_TOKEN;
Host: github.com

在这个示例中,通过JavaScript在二级域名上设置的cookie被发送旁边合法的cookie字段中,并设置到父域名里。如果域名,路径,Secure和HttpOnly属性未设置的话,根本 没有方法去判断哪个cookie来自哪里。

这对大部分web服务器来说是一个大问题,因为在一个域及其子域中的cookies的顺序并不是有RFC6265指定的,并且web浏览器可以选择以任何顺序发送它们。

对于Rack–为Rails和Sinatra提供动力的web服务器界面,包括其他的,cookis解析如下:

def cookies
  hash = {}
  cookies = Utils.parse_query(cookie_header, ';,')
  cookies.each { |k,v| hash[k] = Array === v ? v.first : v }
  hash
end

如果在Cookie:header里有不止一个有着相同名字的cookie时,第一个cookie将会被假定成任意值。

这是一个很显而易见的攻击:几周之前,安全专家Egor Homakov在博客中就用这个方法证明了该攻击确实存在.这个漏洞的影响是不严重的(每次登录后,跨站点伪造请求的令牌会被重置,所以它们不会一直固定不变),但这是个非常实际的例子,人们可以很容易伪造注销用户,令人很郁闷.这使得我们必须尽快完成把GitHub页面迁移的他们自己的域名,但只留给我们几周的时间(到迁移完成之前),在这期间我们必须减轻已知的攻击数量. 幸运的是,已知的攻击在服务端很容易减轻.我们预想到会有一些其他的攻击,这些攻击或者很难处理,或者根本不可能存在.那么让我们一起看看这些它们. 

免受cookie抛出的伤害

第一步是减轻cookie抛出造成的攻击.这个攻击暴露出浏览器将会发送2个相同名字的cookie令牌,不让我们知道它们是设置在哪个域名上的.

我们没法判断每个cookie是来自哪里的,但如果我们跳过cookie的解析,我们就能看出每个请求是否包含2个相同的_session的cookie.这个极有可能是由于有些人从二级尝试域名抛出这些cookie,所以我们不是猜测哪个cookie是合法的,哪个是被抛过来的,而是简单地通知浏览器在继续执行之前放弃二级域名上设置的cookie.

为了完成这个示例,我们创造了一个特殊的响应:我们让浏览器跳转到刚刚请求的URL,但带着一个Set-Cookie的header,这个header放弃了二级域名上的cookie. 

GET /libgit2/libgit2 HTTP/1.1
Host: github.com
Cookie: logged_in=yes; _session=EVIL_SESSION_TOKEN; _session=THIS_IS_A_SESSION_TOKEN;

 

HTTP/1.1 302 Found
Location: /libgit2/libgit2
Content-Type: text/html
Set-Cookie: _session=; Expires=Thu, 01-Jan-1970 00:00:01 GMT; Path=/; Domain=.github.com;

我们决定按照Rack中间件来实现这个功能.这种方式在 应用运行之前可以执行检查cookie和顺序重定向的工作. 

当触发Rack的中间件时,在用户不会意识到的情况下,这个重定向会自动发生,并且第二个请求将只会包含一个_session的cookie:合法的那一个.

这个”破解”足够减缓大部分人所遇到的直接抛出cookie的攻击,但还有一些更复杂的攻击也需要我们思考一下.

Cookie路径方案

如果一个恶意的cookie设置到一个具体的路径,这个路径不是根路径(例如,/notifications),当用户访问github.com/notifications时,浏览器会发送那个cookie,当我们在根路径上清除这个cookie时,我们的header不会起作用.

document.cookie = "_session=EVIL_SESSION_TOKEN; Path=/notifications; Domain=.github.com"

 

GET /notifications HTTP/1.1
Host: github.com
Cookie: logged_in=yes; _session=EVIL_SESSION_TOKEN; _session=THIS_IS_A_SESSION_TOKEN;

 

HTTP/1.1 302 Found
Location: /notifications
Content-Type: text/html
# This header has no effect; the _session cookie was set
# with `Path=/notifications` and won't be cleared by this,
# causing an infinite redirect loop
Set-Cookie: _session=; Expires=Thu, 01-Jan-1970 00:00:01 GMT; Path=/; Domain=.github.com;

这个方案非常直截了当,虽然不太雅:对于任何指定的请求URL,如果其路径部分匹配请求的URL,浏览器将只会发送一个恶意的JavaScript cookie.所以我们只需要在每个路径的元素上放弃这个cookie就可以了.  

HTTP/1.1 302 Found
Location: /libgit2/libgit2/pull/1457
Content-Type: text/html
Set-Cookie: _session=; Expires=Thu, 01-Jan-1970 00:00:01 GMT; Path=/; Domain=.github.com;
Set-Cookie: _session=; Expires=Thu, 01-Jan-1970 00:00:01 GMT; Path=/libgit2; Domain=.github.com;
Set-Cookie: _session=; Expires=Thu, 01-Jan-1970 00:00:01 GMT; Path=/libgit2/libgit2; Domain=.github.com;
Set-Cookie: _session=; Expires=Thu, 01-Jan-1970 00:00:01 GMT; Path=/libgit2/libgit2/pull; Domain=.github.com;
Set-Cookie: _session=; Expires=Thu, 01-Jan-1970 00:00:01 GMT; Path=/libgit2/libgit2/pull/1457; Domain=.github.com;

当谈到cookie时,我们需要在服务端做关联.我们唯一目的是用这个强力方式清楚那些cookie,这种方式虽然暴力,但完成github.io的迁移后,效果非常好. 

Cookie溢出

让我们加强我们的游戏:另一种攻击将会执行,它利用RFC 6265没有明确指明一种cookie的溢出行为.大部分web服务器/接口,包括Rack,假定cookie的名字可以加密(如果他们包含不是ASCII的字符时,这就是个疯狂的假设),所以当生成cookie列表时不会溢出:

cookies = Utils.parse_query(string, ';,') { |s| Rack::Utils.unescape(s) rescue s }

这就允许一个恶意用户去设置一个cookie,这个cookie能被web框架理解成_session,尽管在浏览器里这个cookie的名字并不是_session.这个攻击会把没必要溢出的cookie字符溢出掉:

GET / HTTP/1.1
Host: github.com
Cookie: logged_in=yes; _session=chocolate-cookie; _%73ession=bad-cookie; 

 

{
  "_session" : ["chocolate-cookie", "bad-cookie"]
}

如果我们试着丢弃Rack产生的cookie列表中的第二个,我们的header就会失效.在Rack解析以后,我们会失去重要的信息:通过加密后的cookie名字和web框架接收到的名字将不一致.

# This header has no effect: the cookie in
# the browser is actually named `_%73ession`
Set-Cookie: _session=; Expires=Thu, 01-Jan-1970 00:00:01 GMT; Path=/; Domain=.github.com;

为了解决这个问题,我们必须跳过Rack的cookie解析,可以通过禁用不溢出,然后找到所有和我们目标匹配的那些cookie名字.

cookie_pairs = Rack::Utils.parse_query(cookies, ';,') { |s| s }
cookie_pairs.each do |k, v|
  if k == '_session' && Array === v
    bad_cookies << k
  elsif k != '_session' && Rack::Utils.unescape(k) == '_session'
    bad_cookies << k
  end
end

这种方式我们可以丢弃对的cookie(它或者设置成_session,或者作为溢出的偏差).在这种中间件的帮助下,我们可以解决所有的能在服务端解决的cookie抛出引起的攻击.不幸的是,我们意识到有另一种攻击会使得中间件的保护失效.

Cookie溢出

如果你遇到了cookie的问题,我为你惋惜. 我已经有了99个cookie,我的域名不能再增加一个了.

这是一个稍微更高级的攻击,它暴露出所有web浏览器对每个域名设置的cookie的数量限制.

比如,火狐设置的数量限制是150,谷歌浏览器设置的是180.问题是这个限制不是在每个cookie的域名属性上设置的,而是通过cookie设在的实际域名来定义的.一个单独的HTTP请求访问主域名和子域名上的任一页面,将会发送最大数量的cookie,但哪些cookie被使用的规则确实没有定义的.

例如谷歌浏览器不会关心父域名上的那些cookie,这些cookie是通过HTTP设置或者用Secure设置的:它将会发送180个新的cookie.这使得非常容易"剔除"每一个单独的从父域名过来的cookie,并用一些子域名上用JavaScript运行的假的cookie来替代它们:

for (i = 0; i < 180; i++) {
    document.cookie = "cookie" + i + "=chocolate-chips; Path=/; Domain=.github.com"
}

在子域名上设置了180个这样的cookie之后,所有从父域名过来的cookie就消失了.如果现在我们终止我们刚刚设置的cookie,也包含JavaScript那部分,那么子域名和父域名上的cookie列表就会变空:

for (i = 0; i < 180; i++) {
    document.cookie = "cookie" + i + "=chocolate-chips; Path=/; Domain=.github.com; Expires=Thu, 01-Jan-1970 00:00:01 GMT;"
}

/* all cookies are gone now; plant the evil one */
document.cookie = "_session=EVIL_SESSION_TOKEN; Path=/; Domain=.github.com"

这允许我们执行一个只带有一个_session的cookie的单独的请求:这个cookie是我们用JavaScript创造的.原来的Secure和HttpOnly在_session的cookie里没有了,并且没有方法在web服务端检测发送的cookie既不是Secure,HttpOnly,也不是在父域名中设置的,但是完全虚构的.

在服务端只设置一个_session的cookie,就没有方法知道cookie是否被抛出了.即使我们发现了一个不合法的cookie,这样的攻击也仅能把用户从GitHub注销.

结论

正如我们看到的,通过在浏览器溢出cookie,我们可以制造带有恶意cookie的请求,这些请求不能在服务端阻隔.这里没有什么新的知识:Egnor的原始概念攻击的证据和暴露在这里的变种攻击都早已被世人所知.

现在看起来,在子域名上控制用户自定义的内容是一种安全的自杀行为,尤其在谷歌浏览器当前实现方案下,更加剧了这种自杀行为.火狐处理父域和子域上cookie区别的方式更优雅(用更一致的排序来发送它们,并且分离它们的存储来防止子域的溢出),谷歌浏览器就没有这种区别,并且对通过JavaScript设置的cookie和服务器通过Secure,HttpOnly设置的cookie一视同仁,导致一个非常完美的抛出攻击.

不管如何,通过HTTP header来传输cookie的行为是模糊的和依赖于实现的,迟早会有人提出另一种跨域抛出cookie的方式,和目标浏览器无关.

当cookie抛出的攻击并不是太危险的(比如,拦截用户session,或者实行网络欺诈/骚扰用户是不太可能的),它们会直截了当的进行,这非常使人恼火.

我们希望这篇文章能帮助大家提高这些攻击问题的防范意识和不通过迁移域名来防止这些攻击的困难点,所以迁移域名是一个激进的但最终必须的措施.

via https://github.com/blog/1466-yummy-cookies-across-domains 

via http://www.oschina.net/translate/yummy-cookies-across-domains 

 

Linux:利用ModSecurity防御暴力破解

在阅读本文前,先简单了解下什么是ModSecurity,ModSecurity是一个入侵探测与阻止的引擎.它主要是用于Web应用程序所以也可以叫做Web应用程序防火墙,相信不少商业WAF的签名开发同学也参考了ModSecurity的规则吧。

背景:

上周Wordpress网站遭受了大规模的暴力破解攻击,攻击者首先扫描互联网上的Wordpress网站,然后利用Web服务器组建的僵尸网络不断尝试用户名和密码试图登录管理界面。攻击者使用了超过9万台Web服务器来进行暴力破解。本文借用此例,来介绍下如何利用ModSecurity防御Wordpress的暴力破解。

常规的缓解暴力破解方法如下:

1:更改admin默认账户名称,或直接删除admin,添加一个新的管理员帐户。2:使用双因素认证 3:使用插件限制登录4:使用.htpasswd对访问特定页面实现用户名和密码验证。

这些都有现成的方法去实现了,这里就介绍一下用ModSecurity V2.7.3来保护Wordpress,防止暴力破解。

1:Wordpress的登录过程分析

下图为Wordpress的登录页面:

用户登录之后,发送请求到WP-loing.php页面,HTTP请求包内容如下:

POST /wordpress/wp-login.php HTTP/1.1
Host: mywordpress.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:12.0) Gecko/20100101 Firefox/12.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*; q=0.8
Accept-Language: en-us,en;q=0.5
DNT: 1
Referer: http://mywordpress.com/wordpress/wp-login.php
Content-Type: application/x-www-form-urlencoded
Via: 1.1 owaspbwa.localdomain
Connection: Keep-Alive
Content-Length: 73

log=administrator&pwd=pass123&submit=Login+%C2%BB&redirect_to=wp-admin%2F

payload部分包含了用户名和密码,以及登录成功后转向的页面。OK,了解数据包结构之后,我们可以创建规则,防止未经授权的访问。

2:检查Rerfer

正常的用户登录Wordpress,在数据包头部会包含一个Referer字段,但是通过人工编写的程序,很多不会包含Referer字段,直接发送登录请求到wp-login.php页面,所以,我们可以根据此创建一个ModSecurity规则来检查Rerfer字段信息:

SecRule REQUEST_METHOD "@streq POST" "chain,id:'1',phase:2,t:none,block,log,msg:'Warning: Direct Login Missing Referer.'"
  SecRule REQUEST_FILENAME "@pm /wp-login.php /wp-admin/" "chain"
    SecRule &REQUEST_HEADERS:Referer "@eq 0"

当然通过脚本,很容易实现Rerfer伪造,所以还需要接下来的规则一起配合。

3:限制访问的IP如果你不想修改默认管理员帐号,可以添加一个规则只允许特定的IP访问管理页面,如下:

SecRule REQUEST_METHOD "@streq POST" "chain,id:'1',phase:2,t:none,block,log,msg:'Warning: Direct Login Missing Referer.'"
  SecRule REQUEST_FILENAME "@pm /wp-login.php /wp-admin/" "chain"
    SecRule ARGS:log "@streq admin" "chain"
      SecRule REMOTE_ADDR "!@ipMatch 72.192.214.223"

在这个例子里,只允许名称为freebuf的管理员帐户通过72.192.214.223的IP地址来访问。

4:跟踪管理员帐户的登录尝试

我们可以通过ModSecurity的规则来block掉恶意IP,以下为登录失败的返回包:

HTTP/1.1 200 OK
Date: Fri, 11 May 2012 03:24:53 GMT
Server: Apache
Expires: Wed, 11 Jan 1984 05:00:00 GMT
Last-Modified: Fri, 11 May 2012 03:24:54 GMT
Cache-Control: no-cache, must-revalidate, max-age=0
Pragma: no-cache
Vary: Accept-Encoding
Content-Length: 1697
Connection: close
Content-Type: text/html; charset=UTF-8WordPress › Login

WordPress

Error: Incorrect password.

可以看到状态码为200,而且返回的数据包中包含了Incorrect password,据此可以创建以下规则:

SecRule REQUEST_FILENAME "@streq /wordpress/wp-login.php" "chain, phase:4,id:999323,t:none,block,msg:'Authentication Failure Violation .',logdata:'Number of Authentication Failures: %{ip.failed_auth_ attempt}'"
  SecRule REQUEST_METHOD "@streq POST" "chain"
    SecRule ARGS:log "@streq admin" "chain"
      SecRule RESPONSE_STATUS "200" "chain"
        SecRule RESPONSE_BODY "@contains Error:Incorrect password." "chain,setvar:ip.failed_auth_attempt=+1,expirevar:ip.failed_auth_attempt=60"
          SecRule IP:FAILED_AUTH_ATTEMPT "@gt 5"

5:设置验证请求的次数

ModSecurity可以在指定的时间内跟踪请求的数量,设置阀值来进行阻断攻击,在它的规则集里已经个包含了该规则,modsecurity_crs_10_setup.conf

如下:

#
# -- [[ Brute Force Protection ]] ---------------------------------------------------------
#
# If you are using the Brute Force Protection rule set, then uncomment the following
# lines and set the following variables:
# - Protected URLs: resources to protect (e.g. login pages) - set to your login page
# - Burst Time Slice Interval: time interval window to monitor for bursts
# - Request Threshold: request # threshold to trigger a burst
# - Block Period: temporary block timeout
#
SecAction \
  "id:'900014', \
  phase:1, \
  t:none, \
  setvar:'tx.brute_force_protected_urls=/wp-login.php', \
  setvar:'tx.brute_force_burst_time_slice=60', \
  setvar:'tx.brute_force_counter_threshold=10', \
  setvar:'tx.brute_force_block_timeout=300', \
  nolog, \
  pass"

注意修改 setvar:’tx.brute_force_protected_urls=/wp-login.php‘,

设置完毕后,激活modsecurity_crs_11_brute_force.conf

 

#
# Anti-Automation Rule for specific Pages (Brute Force Protection)
# This is a rate-limiting rule set and does not directly correlate whether the
# authentication attempt was successful or not.
#
#
# Enforce an existing IP address block and log only 1-time/minute
# We don't want to get flooded by alerts during an attack or scan so
# we are only triggering an alert once/minute.  You can adjust how often
# you want to receive status alerts by changing the expirevar setting below.
#
SecRule IP:BRUTE_FORCE_BLOCK "@eq 1" "chain,phase:1,id:'981036',block,msg:'Brute Force Attack Identified from %{tx.real_ip} (%{tx.brute_force_block_counter} hits since last alert)',setvar:ip.brute_force_block_counter=+1"
	SecRule &IP:BRUTE_FORCE_BLOCK_FLAG "@eq 0" "setvar:ip.brute_force_block_flag=1,expirevar:ip.brute_force_block_flag=60,setvar:tx.brute_force_block_counter=%{ip.brute_force_block_counter},setvar:ip.brute_force_block_counter=0"
#
# Block and track # of requests but don't log
SecRule IP:BRUTE_FORCE_BLOCK "@eq 1" "phase:1,id:'981037',block,nolog,setvar:ip.brute_force_block_counter=+1"
#
# skipAfter Checks
# There are different scenarios where we don't want to do checks -
# 1. If the user has not defined any URLs for Brute Force Protection in the 10 config file
# 2. If the current URL is not listed as a protected URL
# 3. If the current IP address has already been blocked due to high requests
# In these cases, we skip doing the request counts.
#
SecRule &TX:BRUTE_FORCE_PROTECTED_URLS "@eq 0" "phase:5,id:'981038',t:none,nolog,pass,skipAfter:END_BRUTE_FORCE_PROTECTION_CHECKS"
SecRule REQUEST_FILENAME "!@within %{tx.brute_force_protected_urls}" "phase:5,id:'981039',t:none,nolog,pass,skipAfter:END_BRUTE_FORCE_PROTECTION_CHECKS"
SecRule IP:BRUTE_FORCE_BLOCK "@eq 1" "phase:5,id:'981040',t:none,nolog,pass,skipAfter:END_BRUTE_FORCE_PROTECTION_CHECKS"
#
# Brute Force Counter
# Count the number of requests to these resoures
#
SecAction "phase:5,id:'981041',t:none,nolog,pass,setvar:ip.brute_force_counter=+1"
#
# Check Brute Force Counter
# If the request count is greater than or equal to 50 within 5 mins,
# we then set the burst counter
#
SecRule IP:BRUTE_FORCE_COUNTER "@gt %{tx.brute_force_counter_threshold}" "phase:5,id:'981042',t:none,nolog,pass,t:none,setvar:ip.brute_force_burst_counter=+1,expirevar:ip.brute_force_burst_counter=%{tx.brute_force_burst_time_slice},setvar:!ip.brute_force_counter"
#
# Check Brute Force Burst Counter and set Block
# Check the burst counter - if greater than or equal to 2, then we set the IP
# block variable for 5 mins and issue an alert.
#
SecRule IP:BRUTE_FORCE_BURST_COUNTER "@ge 2" "phase:5,id:'981043',t:none,log,pass,msg:'Potential Brute Force Attack from %{tx.real_ip} - # of Request Bursts: %{ip.brute_force_burst_counter}',setvar:ip.brute_force_block=1,expirevar:ip.brute_force_block=%{tx.brute_force_block_timeout}"
SecMarker END_BRUTE_FORCE_PROTECTION_CHECKS

6:使用SecGuardianLog

从 1.9版本后,ModSecurity 支持一个新的指令,SecGuardianLog,设计此指令用于把所有允许数据通过管理日志功能发送到另一个程序。自从 apache部署成典型的多进程方式,信息共享变得困难了,这一想法就是部署一个独立的外部进程使用状态机的方式去观察所有的请求,提供额外的保护。使用方法如下:

语法: SecGuardianLog |/path/to/httpd-guardian
示例: SecGuardianLog |/usr/local/apache/bin/httpd-guardian
范围: Main
版本: 2.0.0

而且SecGuardianLog也可以和 SnortSam协同工作(http://www.snortsam.net)。如果已经配置过 httpd-guardian(具体介绍请查看源代码)你只需要在 apache配置中添加一行就可以部署它:

SecGuardianLog |/path/to/httpd-guardian

规则如下:

# If defined, execute this command when a threshold is reached
# block the IP address for one hour.
# $PROTECT_EXEC = "/sbin/blacklist block %s 3600";
# $PROTECT_EXEC = "/sbin/samtool -block -ip %s -dur 3600 snortsam.example.com";
my $PROTECT_EXEC;

# For testing only:
# $PROTECT_EXEC = "/sbin/blacklist-webclient %s 3600";

# Max. speed allowed, in requests per
# second, measured over an 1-minute period
my $THRESHOLD_1MIN = 2; # 120 requests in a minute

跟踪httpd守护进程数量,如果超过了限制,可以执行一些操作,如封锁IP一小时。

了解了一些ModSecurity的防止暴力破解规则之后,同志们可不要对freebuf进行破解,freebuf服务器小心脏经不起折腾,而且到时候IP被封可别找小编解封哦!:)

原文:http://blog.spiderlabs.com/2013/04/defending-wordpress-logins-from-brute-force-attacks.html 

VIA:http://www.freebuf.com/articles/web/8749.html 

 

 

Linux:SchoolTool:先进的学院管理和信息系统

SchoolTool是一个基于网页的开源免费学生信息系统,为世界各地的学校而设计。它是由Shuttleworth研发并发布,基于翻译、定位和自动化部署的有力支持,通过 Ubuntu Linux 安装程序包管理系统 更新。

SchoolTool是经GPL2许可,使用 Zope 3 框架并用 Python 语言编写。这个项目的主要目标是创建一个简单的turnkey模式(译者注:一个“交钥匙”的“工程项目管理模式”)学生管理和信息系统,包括中小学人数统计、学分表、出勤、日历和报告。

功能

  • 可定制学生和教师的人数统计和其他个人的数据
  • 为教师,学生和监护人提供联人管理
  • 教师学分表
  • 全校评估数据收集和报告卡
  • 班级到场人数和每日出勤分数
  • 学校,群组,个人和资源预定日历
  • 跟踪和管理学生的干预措施

安装SchoolTool

SchoolTool核心开发团队强烈建议和推荐在Ubuntu 12.04或之后版本安装SchoolTool。他们为多个系统创建了软件包,但其核心开发团队不支持它们。

SchoolTool是在官方软件仓库中找到的,所以,我们可以用命令来安装它:

$ sudo apt-get install schooltool

另外,可以用PPA来获取更新版本和开发版本。

$ sudo add-apt-repository ppa:schooltool-owners/ppa

或者

$ sudo add-apt-repository ppa:schooltool-owners/dev

使用命令更新软件源列表并最后用命令安装SchoolTool:

$ sudo apt-get install schooltool

访问SchoolTool

打开你的浏览器在地址栏中输入 http://localhost:7080

如果你想通过远程客户端打开它,编辑文件 /etc/schooltool/standard/paste.ini

$ sudo nano /etc/schooltool/standard/paste.ini

设置主机值为0.0.0.0 如下所示。

host = 0.0.0.0

保存并关闭文件。重启schoolTool服务。

$ sudo service schooltool restart 

现在,你可以从你的浏览器上用URL http://ip-address:7080 来访问SchoolTool网页控制台。你将看到一个空白的日历,如下图所示。

Linux:SchoolTool:先进的学院管理和信息系统
Linux:SchoolTool:先进的学院管理和信息系统

初始化配置,更改管理员密码

SchoolTool默认的管理员账户是“ manager ”,密码是“ schooltool ”。登录使用以上认证。

Linux:SchoolTool:先进的学院管理和信息系统
Linux:SchoolTool:先进的学院管理和信息系统

在上面定位到 Home 按钮。点击 Password 下方的 Setting 部分。输入两次旧密码和新密码并单击Apply。

Linux:SchoolTool:先进的学院管理和信息系统
Linux:SchoolTool:先进的学院管理和信息系统

服务设置

登录管理员账户。在Server部分,你将发现你的SchoolTool服务器的细节。

Linux:SchoolTool:先进的学院管理和信息系统
Linux:SchoolTool:先进的学院管理和信息系统

设置外发邮件

SchoolTool并不像Sendmail或Postfix扮演着邮件服务器的工作。它将像邮件客户端一样发送邮件,如Thunderbird, Evolution。

若要在SchoolTool中启用邮件功能,登录管理账户并转到Server列表。点击 Outgoing Email 链接。在那之后,点击黄色铅笔图标去更改邮件设置。填充smtp,Email和password并单击apply。

Linux:SchoolTool:先进的学院管理和信息系统
Linux:SchoolTool:先进的学院管理和信息系统

设置日历

按照你的区域位置设置日历很重要。点击Server部分的 Calendar 列表。选择你的时区,我的设置是 Asia/Kolkatta

Linux:SchoolTool:先进的学院管理和信息系统
Linux:SchoolTool:先进的学院管理和信息系统

转到其他链接,如Errors,Tabs和Pack Database。管理操作系统是不言而喻的。按照你的需求阅读和改变设置。

设置学校

现在我们来介绍简明又重要的部分,它需要我们花费更多的时间和精力来完成。本文并不能覆含所有内容,所以我推荐你去访问SchoolTool官方文档,一个接一个仔细浏览每一部分,按照要求设置你的学校。完成整个学校的设置需要花费可能会花费几个小时甚至几天的时间。别害怕,它并不困难:SchoolTool团队在其网站为用户充分准备了自我帮助的文档和截图。你不必去其他任何地方学习SchoolTool,通过SchoolTool文档页就能学习并DIY。

参考文献:

 

via: http://www.unixmen.com/schooltool-advanced-school-management-information-system/

本文由 LCTT 原创翻译,Linux中国 荣誉推出

译者:Vito 校对:Caroline

来源:https://linux.cn/article-2034-1.html

Linux:使用 BFO 方式安装 Fedora 20

你是不是还在使用传统的下载-安装的方式进行 Fedora 的安装呢?是不是觉得每次下载不仅花费时间,而且镜像文件还占用了不少硬盘空间(虽说目前主流配置都是 T 级别的)呢?下面为你介绍一种长久以来低调存在,但非常高效的安装方法:BFO。

感谢 tiansworld 来稿

什么是 BFO?

BFO 即 boot.fedoraproject.org,是一种能够引导主机,通过网络进行安装或运行其它介质的方式。它与 pxeboot 环境的工作方式很像。详细介绍可以参考官方说明

怎样使用 BFO?

BFO 拥有提供了用于分别能够用于 DVD/CD、U 盘、软盘和 lkrn 镜像的文件。文件体积非常的小,因此老式小容量的 U 盘便可胜任。点击此下载各种介质引导文件

以 U 盘版本为例,在下载对应的 U 盘版本镜像 (bfo.usb) 后,可使用 DD 命令将镜像写至 U 盘。

>dd if=/pathto/bfo.usb of=/dev/sdb

其中 pathto 是下载的 bfo.usb 文件所处的目录。 /dev/sdb 是你要使用的 U 盘设备名。 写好之后,便可以使用它来安装 Fedora 了。

通过 BFO 安装 Fedora

前提:计算机能够连接到稳定的互联网;计算机可以从 U 盘、光盘、软盘等引导,并可将引导顺序设为这些设备优先。

以下还是以 U 盘为例:

1、插入 U 盘,开机。正常情况下,你会看到如图 1 的界面:

Linux:使用 BFO 方式安装 Fedora 20
Linux:使用 BFO 方式安装 Fedora 20

2、再此之后会出现类似图 2 的界面(如果你不幸的只看到黑屏 boot: 那也不要着急,请看后文):

Linux:使用 BFO 方式安装 Fedora 20
Linux:使用 BFO 方式安装 Fedora 20

3、选择 Install currently supported Fedora releases,然后回车,这时你会看到如图 3 一样的目前仍受支持的 Fedora 发行版列表: 

Linux:使用 BFO 方式安装 Fedora 20
Linux:使用 BFO 方式安装 Fedora 20

4、在这里,你可以直接选择你要安装的 Fedora 版本,然后回车,此后将进入 Fedora 的安装过程,如图 5:

Linux:使用 BFO 方式安装 Fedora 20
Linux:使用 BFO 方式安装 Fedora 20

5、当然你也可以在选中要安装的版本后,按 Tab 键,显示或编辑选项。在这里可以将预设的内核、内核镜像、源的地址改为其它你需要的地址。比如可以修改为速度更快的源地址。同时也可以加上 kickstart 文件的路径,以便实现自动化安装。

前面说如果你不幸只看到黑屏 boot: 提示符,那么只要在提示符后面输入这些内容然后回车就可以了。这种情况下最好要有耐心,同时还要仔细,因为不小心输入错误,就需要完全重新输入。你也许会说,这么长串的东西,谁会记得住呢!其实这里面并不复杂,只是三个 URL 而已。第一个是 vmlinuz 所在的位置,第二个是 initrd.img 的位置,还有一个是 repo 的位置。这三个 URL 一般都指向一个源,因此也不是特别复杂。当然出现黑屏 boot: 提示符的机率并不大。

后面的过程就是 Fedora 的安装过程了,无需多说。

总结

BFO 安装方式总体简单方便,省去下载文件的时间。由于它依赖网络,因此对于网络状况良好的环境值得使用。对于网络较差的环境,则可根据情况,适当减少初次安装的软件包,以缩短安装时间。在完成安装后再使用包管理程序陆续安装其它软件包。

via : https://linuxtoy.org/archives/installing-fedora-20-by-bfo.html 

 

Python中django接入新浪微博OAuth的方法介绍

Python中django接入新浪微博OAuth是如何来实现的呢?下面的内容将会通过具体的实例来演示Python中django接入新浪微博OAuth的实现方法及相关技巧:

本文实例讲述了django接入新浪微博OAuth的方法。分享给大家供大家参考。具体分析如下:

最近将网站和新浪微博进行了整合,思路很简单,就是将页面内容和新浪微博联系起来,一个独立内容的页面对于一条微博,自然评论系统只需要使用微博的评论即可。 然后,用户需要发表评论的话,肯定要接入oauth,不可能让用户登录你的网站来发评论吧?没有谁会将自己的账号和密码告诉你的。 查看了新浪微博的授权机制,然后下载了python版的sdk,就可以在django上接入oauth了。

对于oauth很陌生的同学,请先查看OAUTH协议简介

其实流程很简单:

① getrequesttoken ->

② createauthurl ->

③ [user_login: 跳转到新浪登录页面,用户登陆后会跳转回来] ->

④ getaccesstoken ->

⑤ done!

在django上结合python版的sdk的具体实现代码,已经有很详细的注释了:

oauth_views.py文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
基于django的新浪微博oauth views
需要django的session支持
"""

from django.http import HttpResponseRedirect
from weibopy import OAuthHandler, oauth, WeibopError
consumer_key = '' # 设置你申请的appkey
consumer_secret = '' # 设置你申请的appkey对于的secret
class WebOAuthHandler(OAuthHandler):
  def get_authorization_url_with_callback(self, callback, signin_with_twitter=False):
    """Get the authorization URL to redirect the user"""
    try:
      # get the request token
      self.request_token = self._get_request_token()
      # build auth request and return as url
      if signin_with_twitter:
        url = self._get_oauth_url('authenticate')
      else:
        url = self._get_oauth_url('authorize')
      request = oauth.OAuthRequest.from_token_and_callback(
        token=self.request_token, callback=callback, http_url=url
      )
      return request.to_url()
    except Exception, e:
      raise WeibopError(e)
def _get_referer_url(request):
  referer_url = request.META.get('HTTP_REFERER', '/')
  host = request.META['HTTP_HOST']
  if referer_url.startswith('http') and host not in referer_url:
    referer_url = '/' # 避免外站直接跳到登录页而发生跳转错误
  return referer_url
def _oauth():
  """获取oauth认证类"""
  return WebOAuthHandler(consumer_key, consumer_secret)
def login(request):
  # 保存最初的登录url,以便认证成功后跳转回来
  back_to_url = _get_referer_url(request)
  request.session['login_back_to_url'] = back_to_url
  # 获取oauth认证url
  login_backurl = request.build_absolute_uri('/login_check')
  auth_client = _oauth()
  auth_url = auth_client.get_authorization_url_with_callback(login_backurl)
  # 保存request_token,用户登录后需要使用它来获取access_token
  request.session['oauth_request_token'] = auth_client.request_token
  # 跳转到登录页面
  return HttpResponseRedirect(auth_url)
def login_check(request):
  """用户成功登录授权后,会回调此方法,获取access_token,完成授权"""
  # http://mk2.com/&#63;oauth_token=c30fa6d693ae9c23dd0982dae6a1c5f9&oauth;_verifier=603896
  verifier = request.GET.get('oauth_verifier', None)
  auth_client = _oauth()
  # 设置之前保存在session的request_token
  request_token = request.session['oauth_request_token']
  del request.session['oauth_request_token']
  auth_client.set_request_token(request_token.key, request_token.secret)
  access_token = auth_client.get_access_token(verifier)
  # 保存access_token,以后访问只需使用access_token即可
  request.session['oauth_access_token'] = access_token
  # 跳转回最初登录前的页面
  back_to_url = request.session.get('login_back_to_url', '/')
  return HttpResponseRedirect(back_to_url)
def logout(request):
  """用户登出,直接删除access_token"""
  del request.session['oauth_access_token']
  back_to_url = _get_referer_url(request)
  return HttpResponseRedirect(back_to_url)

Python中django接入新浪微博OAuth就是这样,欢迎大家参考。。。。

python如何编写CGI脚本

Python编写CGI脚本是如何来实现的呢?下面的内容将会通过具体的实例来演示Python编写CGI脚本的实现方法及相关技巧:

你是否想使用Python语言创建一个网页,或者处理用户从web表单输入的数据?这些任务可以通过Python CGI(公用网关接口)脚本以及一个Apache web服务器实现。当用户请求一个指定URL或者和网页交互(比如点击””提交”按钮)的时候,CGI脚本就会被web服务器启用。CGI脚本调用执行完毕后,它的输出结果就会被web服务器用来创建显示给用户的网页。

配置Apache web服务器,让其能运行CGI脚本

在这个教程里,我们假设Apache web服务器已经安装好,并已运行。这篇教程使用的Apache web服务器(版本2.2.15,用于CentOS发行版6.5)运行在本地主机(127.0.0.1),并且监听80端口,如下面的Apache指令指定一样:

1
2
3
ServerName 127.0.0.1:80

    Listen 80

下面举例中的HTML文件存放在web服务器上的/var/www/html目录下,并通过DocumentRoot指令指定(指定网页文件所在目录):

1
DocumentRoot "/var/www/html"

现在尝试请求URL:http://localhost/page1.html

这将返回web服务器中下面文件的内容:

1
/var/www/html/page1.html

为了启用CGI脚本,我们必须指定CGI脚本在web服务器上的位置,需要用到ScriptAlias指令:

1
ScriptAlias /cgi-bin/ "/var/www/cgi-bin/"

以上指令表明CGI脚本保存在web服务器的/var/www/cgi-bin目录,请求URL里包含/cgi-bin/的将会搜索这个目录下的CGI脚本。

我们必须还要明确CGI脚本在/var/www/cgi-bin目录下有执行权限,还要指定CGI脚本的文件扩展名。使用下面的指令:

1
2
3
4
 <directory "/var/www/cgi-bin">
  Options +ExecCGI
  AddHandler cgi-script .py
 </directory>

下面访问URL:http://localhost/cgi-bin/myscript-1.py

这将会调用web服务器中下面所示脚本:

1
/var/www/cgi-bin/myscript-1.py

创建一个CGI脚本

在创建一个Python CGI脚本之前,你需要确认你已经安装了Python(这通常是默认安装的,但是安装版本可能会有所不同)。本篇教程使用的脚本是使用Python版本2.6.6编写的。你可以通过下面任意一命令(-V和–version参数将显示所安装Python的版本号)检查Python的版本。

1
2
 $ python -V
 $ python --version

如果你的Python CGI脚本要用来处理用户输入的数据(从一个web输入表单),那么你将需要导入Python cgi模块。这个模块可以处理用户通过web输入表单输入的数据。你可以在你的脚本中通过下面的语句导入该脚本:

1
 import cgi

你也必须修改Python CGI脚本的执行权限,以防止web服务器不能调用。可以通过下面的命令增加执行权限:

1
 # chmod o+x myscript-1.py

Python CGI例子

涉及到Python CGI脚本的两个方案将会在下面讲述:

  • 使用Python脚本创建一个网页
  • 读取并显示用户输入的数据,并且在网页上显示结果

注意:Python cgi模块在方案2中是必需的,因为这涉及到用户从web表单输入数据。

例子1 :使用Python脚本创建一个网页

对于这个方案,我们将通过创建包含一个单一提交按钮的网页/var/www/html/page1.html开始。

1
2
3
4
5
6
 <html>
 <h1>Test Page 1</h1>
 <form name="input" action="/cgi-bin/myscript-1.py" method="get">
 <input type="submit" value="Submit">
 </form>
 </html>

当”提交”按钮被点击,/var/www/cgi-bin/myscript-1.py脚本将被调用(通过action参数指定)。通过设置方法参数为”get”来指定一个”GET”请求,服务器将会返回指定的网页。/var/www/html/page1.html在浏览器中的显示情况如下:

2015629110446275.jpg (640×286)

/var/www/cgi-bin/myscript-1.py的内容如下:

1
2
3
4
5
6
7
 #!/usr/bin/python
 print "Content-Type: text/html"
 print ""
 print "<html>"
 print "<h2>CGI Script Output</h2>"
 print "<p>This page was generated by a Python CGI script.</p>"
 print "</html>"

第一行声明表示这是使用 /usr/bin/python命令运行的Python脚本。”Content-Type: text/html”打印语句是必需的,这是为了让web服务器知道接受自CGI脚本的输出类型。其余的语句用来输出HTML格式的其余网页内容。

当”Submit”按钮点击,下面的网页将返回:

2015629111109379.jpg (640×286)

这个例子的要点是你可以决定哪些信息可以被CGI脚本返回。这可能包括日志文件的内容,当前登陆用户的列表,或者今天的日期。在你处理时拥有所有python库的可能性是无穷无尽的。

例子2:读取并显示用户输入的数据,并将结果显示在网页上

对于这个方案,我们将通过创建一个含有三个输入域和一个提交按钮的网页/var/www/html/page2.html开始。

1
2
3
4
5
6
7
8
9
 <html>
 <h1>Test Page 2</h1>
 <form name="input" action="/cgi-bin/myscript-2.py" method="get">
 First Name: <input type="text" name="firstName"><br />
 Last Name: <input type="text" name="lastName"><br />
 Position: <input type="text" name="position"><br />
 <input type="submit" value="Submit">
 </form>
 </html>

当”Submit”按钮点击,/var/www/cgi-bin/myscript-2.py脚本将被执行(通过action参数指定)。/var/www//html/page2.html显示在web浏览器中的图片如下所示(注意,三个输入域已经被填写好了):

2015629111252493.jpg (640×286)

/var/www/cgi-bin/myscript-2.py的内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 #!/usr/bin/python
 import cgi
 form = cgi.FieldStorage()
 print "Content-Type: text/html"
 print ""
 print "<html>"
 print "<h2>CGI Script Output</h2>"
 print "<p>"
 print "The user entered data are:<br />"
 print "<b>First Name:</b> " + form["firstName"].value + "<br />"
 print "<b>Last Name:</b> " + form["lastName"].value + "<br />"
 print "<b>Position:</b> " + form["position"].value + "<br />"
 print "</p>"
 print "</html>"

正如前面提到,import cgi语句用来确保能够处理用户通过web输入表单输入的数据。web输入表单被封装在一个表单对象中,叫做cgi.FieldStorage对象。一旦开始输出,”Content-Type: text/html”是必需的,因为web服务器需要知道接受自CGI脚本的输出格式。用户输入的数据在包含form[“firstName”].value,form[“lastName”].value,和 form[“position”].value的语句中可以得到。那些中括号中的名称和/var/www/html/page2.html文本输入域中定义的名称参数一致。

当网页上的”Submit”按钮被点击,下面的网页将被返回。

2015629111455279.jpg (640×286)

这个例子的要点就是你可以很容易地读取并显示用户在web表单上输入的数据。除了以字符串的方式处理数据,你也可以用Python将用户输入的数据转化为可用于数值计算的数字。

Python编写CGI脚本就是这样,欢迎大家参考。。。。