安全编程与自定义错误文档创建指南
安全编程
在网络编程中,确保脚本安全至关重要。当编写供网络使用的 CGI 程序时,可能会有数以百万计的人访问,其中不乏心怀不轨者。因此,始终要将安全放在首位。
避免使用 shell 执行命令的风险
在 CGI 脚本中使用 shell 命令存在危险,特别是在命令中使用用户输入时。风险源于 shell 的命令行解析器,它会将某些字符解释为特殊指令,这些字符被称为元字符。例如,在命令
ls -al | grep “passwd”; cat
find . -name “thisfile”
中,管道符 `|`、分号 `;` 和反引号
都是元字符。
为避免元字符带来的风险,可采用以下方法:
-
去除元字符
:使用正则表达式扫描并移除元字符。shell 使用的元字符列表如下:
& ;
‘ \ “ | * ? ~ < > ^ () [] {} $ \n \r
这里的
\n
和
\r
是换行符。
- **使用正则表达式验证输入**:将用户输入缩减为所需的准确数据。例如,请求电子邮件地址或文件路径时,使用正则表达式和绑定运算符
=~` 确保输入有效后再发送到命令行。
在 Perl 中,还可以不通过 shell 调用外部程序,避免嵌入元字符带来的不良影响。例如,不使用
system “grep rafec /etc/passwd”;
,而是使用
system “grep”, “rafec”, “/etc/passwd”;
。
常见问题解答
-
什么是拒绝服务攻击?
拒绝服务攻击旨在拒绝计算机的访问,而非入侵。通常是通过网络向计算机发送大量数据,使其不堪重负,无法响应合法请求。也有一些漏洞允许恶意人员发送特定命令使计算机崩溃。大多数此类攻击发生在网络层面,通常可通过操作系统供应商发布的补丁修复。因此,应始终关注最新的安全问题。 -
如何了解最新的安全问题?
有许多优秀的网站提供安全信息,如 Security Focus(http://www.securityfocus.com/)提供各种安全新闻和信息,也是著名的 Bugtraq 邮件列表的所在地。Windows 用户可能会发现 NTBugtraq(http://www.ntbugtraq.com)网站和邮件列表更有用。 -
如果有人入侵了我的 Web 服务器,我该怎么办?
不要惊慌。如果怀疑系统被入侵,应参考 CERT 入侵者检测清单(http://www.cert.org/tech_tips/intruder_detection_checklist.html)。按照清单步骤操作可确定系统是否被入侵,但结果可能因攻击者的技巧而异。必要时,可聘请专业的安全顾问。如果发现系统被入侵,应将系统离线,并遵循 CERT 文档“Steps for Recovering from a UNIX or NT System Compromise”(http://www.cert.org/tech_tips/root_compromise.html)中的说明(假设服务器运行 UNIX 衍生系统)。
测验与练习
测验
:
1. 为什么扫描表单输入中的元字符很重要?
2. 为什么将 CGI 脚本存储在文档根目录下不是个好主意?
3. 什么会导致缓冲区溢出?
练习
:
1. 在互联网上搜索服务器操作系统的安全信息,确保已修复操作系统的已知问题。
2. 查看 CERT 入侵者检测清单,确保系统未被入侵,熟悉服务器操作系统提供的日志记录机制和其他安全功能,以便在系统被入侵时知道该怎么做。
测验答案
:
1. 必须扫描表单输入中的元字符,以防止它们被传递到 shell 并被解释,从而引发问题。
2. 将 CGI 程序存储在文档目录中可能很危险,因为用户可能会下载源代码。
3. 当变量中放置的数据超过其设计容量时,会导致缓冲区溢出。
创建自定义错误文档
当网站出现问题时,显示自定义错误文档可以使网站更友好。大多数 Web 服务器允许指定自定义文档替代默认文档。
什么是错误文档
请求不存在的 URL 或输入错误的用户名和密码访问受保护页面时,会遇到错误文档。大多数 Web 服务器为每种错误都有默认的错误文档,也允许管理员配置其他文档或 CGI 程序来覆盖默认文档。
默认错误文档虽然能指出请求存在问题,但对帮助用户找到所需内容或解决问题的作用不大。许多互联网用户通过搜索引擎查找页面,如果网站内容重新组织并更改了部分页面的 URL,用户可能会通过搜索引擎找到旧 URL,访问时却得到错误文档,这可能导致用户不再访问该网站。因此,创建自定义错误文档很有必要。
配置 Web 服务器使用自定义错误文档
在使用自定义错误文档之前,需要设置 Web 服务器发送自定义文档而非默认文档。自定义错误文档可以是普通 HTML 文档,也可以使用 CGI 脚本动态生成。以下以 Apache Web 服务器为例进行说明。
Apache Web 服务器对自定义错误文档有强大的支持,可以在多种上下文中指定自定义错误文档,如修改全局配置文件为整个服务器、虚拟主机或特定目录指定错误文档,也可以修改 .htaccess 文件为受该文件管理的网页指定错误文档。
要在 .htaccess 文件中指定自定义错误文档,必须为 Web 服务器启用 FileInfo 覆盖。使用 ErrorDocument 指令指定自定义错误文档的位置和响应的错误。其语法为:
ErrorDocument error-code document-location
错误响应可以通过以下四种方式配置:
| 配置方式 | 说明 |
| ---- | ---- |
| 打印服务器中硬编码的消息 | 这是默认响应 |
| 打印使用 ErrorDocument 指令指定的不同消息 | 例如,要更改 404 错误的消息,可在影响用户查找的 URL 的配置文件中添加
ErrorDocument 404 “Sorry, I couldn’t find that document...”
|
| 将用户重定向到本地 URL | 例如,使用
ErrorDocument 404 /cgi-bin/404_response.cgi
指定错误文档的相对位置 |
| 将用户重定向到另一个 Web 服务器上的 URL | 例如,
ErrorDocument 404 http://home.netscape.com
。但由于基本身份验证的工作方式,外部错误文档链接对 401 未授权错误不起作用 |
使用 HTML 创建基本错误文档
错误文档至少应告诉用户发生了什么问题,提供网站主页的链接,并提供向网站管理员发送电子邮件的方式。例如,以下是一个 404 未找到错误的基本错误文档示例:
<html>
<head>
<title>Document Not Found</title>
</head>
<body>
<h1>Document Not Found</h1>
<p>The document you requested is no longer available at the location that you specified. You can return to our <a href="/index.html">home page</a> or send email to the <a href="mailto:siteadmin@example.com">site administrator</a>.</p>
</body>
</html>
对于其他错误消息,也可以创建类似的文档。对于 401 未授权响应,尤其需要创建自定义文档,帮助用户了解原因或提供申请访问的页面。自定义错误文档应反映网站的外观和感觉,让用户即使遇到错误也能感到“找对地方了”,并通过错误文档上的链接找到所需信息。
使用 CGI 创建高级错误文档
CGI 在创建自定义错误文档方面提供了很大的灵活性。与普通 HTML 错误文档不同,CGI 脚本可以根据用户的请求提供定制内容。
当 CGI 程序因错误被调用时,Apache(和其他符合 NCSA 标准的 Web 服务器)会设置三个不属于正常 CGI 环境的环境变量,这些变量包含有助于构建错误文档的用户请求信息,如下表所示:
| 变量 | 包含内容 |
| ---- | ---- |
| REDIRECT_REQUEST | 导致错误的完整请求,包括请求方法、文件路径和协议 |
| REDIRECT_URL | 实际导致错误的 URL |
| REDIRECT_STATUS | 如果请求成功,将发送给用户的状态代码 |
错误文档的一个常见功能是提供返回引用页面的链接,特别是 404 错误的文档。Web 服务器将包含链接到当前页面的页面存储在环境变量 HTTP_REFERER 中,因此创建返回引用页面的文档非常简单。以下是示例代码:
#!/usr/local/bin/perl
use CGI;
my $query = new CGI;
print $query->header;
print <<HERE;
<html>
<head>
<title>Document Not Found</title>
</head>
<body>
<h1>Document Not Found</h1>
<p>The document you requested is no longer available at the location you specified. You can return to our <a href="/index.html">home page</a> or send email to the <a href="mailto:webmaster\@example.com">webmaster</a>.</p>
HERE
if ($ENV{'HTTP_REFERER'}) {
$referrer = $ENV{'HTTP_REFERER'};
print "<p>You can also go back to the referring page:<br />\n";
print "<a href=\"$referrer\">$referrer</a></p>\n";
}
print "</body>\n</html>\n";
此外,还可以创建程序根据用户请求的路径选择合适的页面并提供链接。例如,对于一个相对较小的网站,每个目录都有一个已知文件提供该目录下所有文档的链接,程序可以根据请求路径判断用户可能需要的页面并提供链接。以下是示例代码:
#!/usr/local/bin/perl
use CGI;
my $query = new CGI;
print $query->header;
print <<HERE;
<html>
<head>
<title>404 Not Found</title>
<head>
<body>
<h1>404 Not Found</h1>
<p>The document that you requested was not found on the server.</p>
<p>You can try looking at the index for that section of the Web site:</p>
<p>
HERE
(undef, $main_path) = split /\//, $ENV{'REDIRECT_URL'};
if ($main_path eq "football") {
print "<a href=\"/football/index.html\">Football Index</a>\n";
}
elsif ($main_path eq "baseball") {
print "<a href=\"/baseball/index.html\">Baseball Index</a>\n";
}
elsif ($main_path eq "basketball") {
print "<a href=\"/basketball/index.html\">Basketball Index</a>\n";
}
else {
print "<a href=\"/index.html\">Go to the home page.</a>\n";
}
print "</p></body></html>\n";
还可以编写更复杂的程序,例如检查请求文件的扩展名,如果是 .htm(或 .HTM),尝试检查是否存在 .html 扩展名的文件。以下是示例代码:
#!/usr/bin/perl
use CGI;
my $query = new CGI;
print $query->header;
print <<HERE;
<html>
<head>
<title>404 Not Found</title>
<head>
<body>
<h1>404 Not Found</h1>
<p>The document that you requested was not found on the server.</p>
<p>
HERE
$extension = substr($ENV{'REDIRECT_URL'}, -3);
if ($extension eq "htm" or $extension eq "HTM") {
if ($extension eq "htm") {
$path_to_file = $ENV{'DOCUMENT_ROOT'} . $ENV{'REDIRECT_URL'} . "l";
$url = $ENV{'REDIRECT_URL'} . "l";
}
elsif ($extension eq "HTM") {
$path_to_file = $ENV{'DOCUMENT_ROOT'} . $ENV{'REDIRECT_URL'} . "L";
$url = $ENV{'REDIRECT_URL'} . "L";
}
if (-e $path_to_file) {
print "Perhaps the file you're looking for is located at \n";
print "the following URL:\n";
print "<a href=\"", $url, "\">", $url, "</a>\n";
}
}
else {
print "You can go to our <a href=\"/index.html\">home page</a>.\n";
}
print "</p>\n";
print "<p>You can also return to the ";
print "<a href=\"", $ENV{'HTTP_REFERER'}, "\">referring page</a>.</p>\n";
print "</body>\n";
print "</html>\n";
需要注意的是,不同的 Web 服务器可能设置不同的环境变量,应研究服务器为 CGI 环境设置的环境变量,找到获取所需信息的合适变量。可以创建一个小的 CGI 程序,包含
print %ENV;
语句,打印所有环境变量的名称和内容。
处理“未找到”错误
大多数网站会定期重新设计,这可能导致部分页面的 URL 发生变化。搜索引擎的索引通常不及时,用户可能会通过旧 URL 访问网站,得到错误文档。
为解决这个问题,可以使用一个脚本,它包含旧 URL 和新 URL 的映射列表。当用户使用旧 URL 访问页面时,脚本会在列表中查找并自动将用户重定向到新 URL,并提醒用户更改书签。
以下是数据文件示例:
/some_page.html /some_other_page.html
/toc.html /sitemap.html
以下是脚本的源代码:
#!/usr/local/bin/perl
use CGI;
use CGI::Carp;
my $query = new CGI;
my $new_urls_file = "new_urls.txt";
my $new_location;
my $requested_url = $ENV{'REDIRECT_URL'};
open (URLS, "< $new_urls_file")
or die "Can't open $new_urls_file";
while (<URLS>) {
my ($old_url, $new_url) = split /\t/;
if ($old_url eq $requested_url) {
$new_location = $new_url;
last;
}
}
close URLS;
print $query->header;
print "<html>\n<head>\n<title>";
if ($new_location) {
print "Page Moved";
}
else {
print "Requested URL Not Found";
}
print "</title>\n</head>\n<body>\n";
if ($new_location) {
print "<h1>Page Moved</h1>\n";
print "<p>The page you're looking for has moved.\n";
print "It is now located at:</p>\n";
print "<p align=\"center\"><font size=\"+1\">";
print "<a href=\"$new_location\">$new_location</a>";
print "</font></p>\n";
}
else {
print "<h1>Requested URL Not Found</h1>\n";
print "<p>The URL you requested does not exist or has been moved.\n";
print "If you'd like, you can return to the \n";
print "<a href=\"/\">home page</a>.</p>\n";
}
print "<p>If you have questions or would like to report a problem \n";
print "send email to <a href=\"mailto:webmaster\@example.com\">";
print "webmaster\@example.com</a>.</p>\n";
print "</body>\n</html>\n";
该脚本的基本结构如下:
1. 指定数据文件的位置并存储在
$new_urls_file
变量中。
2. 从
REDIRECT_URL
环境变量中获取用户最初请求的 URL,存储在
$requested_url
变量中。
3. 打开数据文件,遍历其中的记录,将旧 URL 与用户请求的 URL 进行比较。如果匹配,将
$new_location
变量设置为新 URL,并退出循环。
4. 开始打印页面的 HTML 部分,根据是否找到新 URL 打印不同的标题和内容。
5. 最后打印包含网站管理员电子邮件地址的简短消息和结束 HTML。
通过以上方法,可以提高网站的安全性和用户体验,减少因错误文档导致的用户流失。
安全编程与自定义错误文档创建指南(续)
自定义错误文档的优化与拓展
在创建自定义错误文档时,除了前面提到的基本功能,还可以进行一些优化和拓展,以进一步提升用户体验。
动态内容展示
可以根据不同的错误类型和用户请求,展示更丰富的动态内容。例如,对于 404 错误,可以显示一些热门文章或相关内容的推荐,引导用户继续浏览网站。以下是一个简单的示例代码,展示如何在 404 错误文档中添加热门文章推荐:
#!/usr/local/bin/perl
use CGI;
my $query = new CGI;
print $query->header;
print <<HERE;
<html>
<head>
<title>404 Not Found</title>
</head>
<body>
<h1>404 Not Found</h1>
<p>The document you requested was not found. Here are some popular articles you might be interested in:</p>
<ul>
<li><a href="/popular_article_1.html">Popular Article 1</a></li>
<li><a href="/popular_article_2.html">Popular Article 2</a></li>
<li><a href="/popular_article_3.html">Popular Article 3</a></li>
</ul>
<p>You can also return to our <a href="/index.html">home page</a>.</p>
</body>
</html>
HERE
错误日志记录与分析
在自定义错误文档中添加错误日志记录功能,可以帮助管理员更好地了解网站的错误情况,及时发现潜在问题。可以将错误信息记录到文件或数据库中,以便后续分析。以下是一个简单的示例代码,将错误信息记录到文件中:
#!/usr/local/bin/perl
use CGI;
use Time::Piece;
my $query = new CGI;
print $query->header;
# 获取当前时间
my $now = localtime;
my $timestamp = $now->strftime("%Y-%m-%d %H:%M:%S");
# 获取错误信息
my $error_url = $ENV{'REDIRECT_URL'};
my $error_status = $ENV{'REDIRECT_STATUS'};
# 记录错误信息到文件
open(my $log_fh, '>>', 'error_log.txt') or die "Can't open error log file: $!";
print $log_fh "$timestamp - Error $error_status: $error_url\n";
close($log_fh);
print <<HERE;
<html>
<head>
<title>Error Occurred</title>
</head>
<body>
<h1>An error has occurred</h1>
<p>We're sorry for the inconvenience. Our team has been notified of this issue.</p>
<p>You can return to our <a href="/index.html">home page</a>.</p>
</body>
</html>
HERE
多语言支持
如果网站面向全球用户,提供多语言的错误文档可以提升用户体验。可以根据用户的浏览器语言设置,自动显示相应语言的错误文档。以下是一个简单的示例代码,根据用户的语言设置显示不同语言的 404 错误文档:
#!/usr/local/bin/perl
use CGI;
my $query = new CGI;
print $query->header;
# 获取用户的语言设置
my $lang = $query->http('Accept-Language');
if ($lang =~ /^en/) {
print <<HERE;
<html>
<head>
<title>404 Not Found</title>
</head>
<body>
<h1>404 Not Found</h1>
<p>The page you requested was not found. Please try again later or return to our <a href="/index.html">home page</a>.</p>
</body>
</html>
HERE
} elsif ($lang =~ /^zh/) {
print <<HERE;
<html>
<head>
<title>404 未找到</title>
</head>
<body>
<h1>404 未找到</h1>
<p>您请求的页面未找到。请稍后再试或返回我们的 <a href="/index.html">主页</a>。</p>
</body>
</html>
HERE
} else {
print <<HERE;
<html>
<head>
<title>404 Not Found</title>
</head>
<body>
<h1>404 Not Found</h1>
<p>The page you requested was not found. Please try again later or return to our <a href="/index.html">home page</a>.</p>
</body>
</html>
HERE
}
安全编程与自定义错误文档的综合应用
在实际应用中,安全编程和自定义错误文档的创建是相辅相成的。安全的编程可以减少错误的发生,而自定义错误文档可以在错误发生时提供更好的用户体验。以下是一个综合应用的流程图:
graph TD;
A[用户请求页面] --> B{请求是否成功};
B -- 是 --> C[返回正常页面];
B -- 否 --> D[触发错误];
D --> E[执行安全编程检查];
E --> F{是否存在安全风险};
F -- 是 --> G[记录安全风险信息并阻止请求];
F -- 否 --> H[调用自定义错误文档];
H --> I[根据错误类型和用户请求生成动态内容];
I --> J[记录错误信息];
J --> K[显示自定义错误文档给用户];
总结
通过安全编程和自定义错误文档的创建,可以显著提升网站的安全性和用户体验。在安全编程方面,要注意避免使用 shell 命令带来的风险,对用户输入进行严格验证。在自定义错误文档方面,可以根据不同的需求进行优化和拓展,如动态内容展示、错误日志记录与分析、多语言支持等。同时,要将安全编程和自定义错误文档的创建结合起来,形成一个完整的体系,为用户提供更优质的服务。
在实际开发过程中,要不断测试和优化自定义错误文档,确保其在各种情况下都能正常工作。同时,要关注最新的安全漏洞和技术发展,及时更新安全编程策略,保障网站的安全稳定运行。
超级会员免费看

被折叠的 条评论
为什么被折叠?



