脚本侵入介绍以及错误处理
1.脚本侵入
从浏览器的角度来看,网页只是一个长字符串。浏览器会按顺序处理这个字符串,在此过程中,会显示某些字符,同时按特殊规则解释其他字符(如 <b> 和 <script>)。如果恶意用户可以将某些特殊字符插入到页中,则浏览器将不知道这些字符不应该处于该位置,将作为页的一部分处理它们。 一个简单化的脚本利用的工作方式如下所示。如果应用程序允许用户发布对最新影片的评论以供其他用户阅读,则利用脚本的步骤可以是: 应用程序显示一个用户可以输入评论的窗体。恶意用户编写了一个其中包含 <script> 块的评论。 发送窗体,恶意用户的评论将存储在数据库中。 另一用户访问该站点。在构造页时,应用程序会从数据库中读取评论并将它们放在页中。恶意用户的 <script> 块将写入页中,就好像它是文本评论一样。 当第二个用户的浏览器显示此页时,它将遇到 <script> 块并执行它。 恶意用户还可以使用其他方法来利用脚本。大多数脚本利用都会要求应用程序接受恶意输入,并将其插入到页中(或回显它),浏览器将在该页中执行它。这种利用带来的潜在损害取决于所执行的脚本。它可以是无足轻重的,如在浏览器中弹出的烦人的消息。但是,它也可能会窃取 Cookie、窃取用户输入(如密码),甚至在用户的计算机上运行本机代码(如果对 Internet 安全性的要求不严格),从而造成严重的损害。
大多数脚本利用发生在用户可以将可执行代码(或脚本)插入您的应用程序时。默认情况下,ASP.NET 提供请求验证。只要窗体发送包含任何 HTML,该验证都会引发错误。 您可以使用下列方法防止脚本利用: 对窗体变量、查询字符串变量和 Cookie 值执行参数验证。该验证应包括两种类型的验证:可以将变量转换为所需类型(如转换为整数、日期时间等)的验证,以及所需范围或格式的验证。例如,应该使用 Int32.TryParse 方法来检查应为整数的窗体发送变量,以验证该变量是否确实为整数。而且,还应该检查得到的整数,以验证该值是否在所需值范围之内。 将值写回响应时,向字符串输出应用 HTML 编码。这有助于确保用户提供的所有字符串输入将以静态文本形式呈现在浏览器中,而不是呈现为可执行的脚本代码或已解释的 HTML 元素。 HTML 编码使用 HTML 保留字符转换 HTML 元素,以便显示它们而不是执行它们。 向字符串应用 HTML 编码 显示字符串之前,调用 HtmlEncode 方法。HTML 元素会转换为浏览器将显示(而不解释为 HTML)的字符串表示形式。 下面的示例说明 HTML 编码。在第一个实例中,在显示用户输入之前对其进行编码。在第二个实例中,在显示数据库中的数据之前对其进行编码。 注意: 只有通过添加 @ Page 属性 ValidateRequest="false" 在页中禁用请求验证时,此示例才起作用。建议不要在成品应用程序中禁用请求验证,因此,请确保在查看本示例之后重新启用请求验证。
private void Button1_Click(objectsender, System.EventArgs e) {
Label1.Text = Server.HtmlEncode(TextBox1.Text);
Label2.Text = Server.HtmlEncode("<script>alert('hello hello');</script>");
}
防止脚本利用的主要方法就是决不信任来自用户的信息。假定从浏览器发送到您的应用程序的任何数据都包含恶意脚本。 同样,每次将字符串写入页时,您都应该假定字符串可能包含恶意脚本(除非您自己以编程方式创建了字符串)。例如,在从数据库中读取字符串时,您应该假定它们可能包含恶意脚本。安全意识很强的开发人员甚至不信任他们自己的数据库,理由是他们认为恶意用户可能有办法篡改数据库。 ASP.NET 为您提供了几种有助于防止脚本利用的方法: ASP.NET 对查询字符串、窗体变量和 Cookie 值执行请求验证。默认情况下,如果当前的 Request 包含 HTML 编码的元素或某些 HTML 字符(如表示长破折号的 —),则 ASP.NET 页框架将引发一个错误。 如果要在应用程序中显示字符串,但不信任这些字符串,可以在响应中回写字符串时将 HTML 编码应用于这些字符串。例如,进行编码后,标记 <b> 将变成 <b>。如果您要显示的字符串来自您尚未确定信任其内容的数据库时,您可能会这样做。 如果希望应用程序接受某个 HTML(例如,来自用户的某些格式设置说明),那么,在将这个 HTML 提交给服务器之前,应在客户端对其进行编码。 为了防止 SQL 语句利用,决不能串联字符串创建 SQL 查询。相反,使用参数化查询并将用户输入分配给参数对象。有关详细信息,请参见数据适配器命令中的参数。 始终对一组预期值执行窗体输入验证以及字符串格式设置/类型验证。例如,如果特定的窗体变量应为整数,则使用 Int32..::.TryParse 方法验证该值是否确实为整数,并使用范围检查帮助确保该值位于可接受范围内。
2.占位符,SQL注入?
参考:
http://hi.baidu.com/ncheng/blog/item/e62e7d519f600a14367abed8.html
http://blog.csdn.net/yan465942872/article/details/6753957
不同的数据库服务器sql语句中参数的占位符不同,上面用的是oracle,参数占位符是冒号(:)加名字,在sqlserver中是用@符号加名字作为占位符,而在mysql中用问号(?)加名字来作为参数占位符,不同的数据库中参数的表示符号不一样,这个需要注意
转义不是sqlserver来做的 而是 动态语言来做的也就是net java等
可以发现最外面的单引号被转义了,也就是说占位符后的sql语句是这样的
delete from user where user.id=\'w' or '2'='2\';
而且仔细看会发现在是一个字符一个字符的解析,该转义的都已经转义,正如他一句注释中写的Better safe than sorry.所以最终,占位符确实不存在注入问题
//mysql?? SELECT BookId, Title, Author, Price from BOOKS WHERE (Title LIKE ?) //使用 SqlCommand 命名参数的查询可能如下所示: SELECT BookId, Title, Author, Price from BOOKS WHERE (Title LIKE @title) //使用 OracleCommand 命名参数的查询可能如下所示: SELECT BookId, Title, Author, Price from BOOKS WHERE (Title LIKE :title) INSERT INTO ShoppingCart (BookId, CustId, Quantity) Values (?, ?, ?) INSERT INTO ShoppingCart (BookId, CustId, Quantity) Values (@bookid, @custid, @quantity) UPDATE ShoppingCart SET (BookId = ?, CustId = ?, Quantity = ?) WHERE (BookId = ? AND CustId = ?) UPDATE ShoppingCart SET (BookId = @bookid, CustId = @custid, Quantity = @quantity) WHERE (BookId = @bookid AND CustId = @custid) DELETE FROM ShoppingCart WHERE (BookId = ? AND CustId = ?) DELETE FROM ShoppingCart WHERE (BookId = @bookid AND CustId = @custid)
如何:处理页级别错误
如何:显示安全错误信息
将应用程序配置为不向远程用户显示错误 在应用程序的 Web.config 文件中,对 customErrors 元素进行以下更改: 将 mode 属性设置为 RemoteOnly(区分大小写)。这就将应用程序配置为仅向本地用户(即,您 - 开发人员)显示详细的错误。 (可选)包括指向应用程序错误页的 defaultRedirect 属性。 (可选)包括将错误重定向到特定页的 <error> 元素。例如,您可以将标准 404 错误(未找到页)重定向到您自己的应用程序页。 下面的代码示例显示 Web.config 文件中的典型 customErrors 块。
<customErrors mode="RemoteOnly" defaultRedirect="AppErrors.aspx"> <error statusCode="404" redirect="NoSuchPage.aspx"/> <error statusCode="403" redirect="NoAccessAllowed.aspx"/> </customErrors>
包括错误处理
在任何可能生成错误的语句周围使用一个 try-catch 块。 可以选择使用 IsLocal 属性对本地用户进行测试并相应地修改错误处理。值 127.0.0.1 等效于 localhost,指示浏览器与 Web 服务器位于同一台计算机上。 下面的代码示例显示一个错误处理块。如果发生错误,则用有关消息的详细信息加载 Session 状态变量,然后应用程序显示可以读取 Session 变量并显示错误的页。(有意写入此错误以便不向用户提供任何可利用的详细信息。)如果用户是本地用户,则提供不同的错误详细信息。在 finally 块中,释放开放式资源
try { sqlConnection1.Open(); sqlDataAdapter1.Fill(dsCustomers1); } catch (Exception ex) { if(Request.IsLocal) { Session["CurrentError"] = ex.Message; } else { Session["CurrentError"] = "Error processing page."; } Server.Transfer("ApplicationError.aspx"); } finally { this.sqlConnection1.Close(); }
创建全局错误处理程序
如果您具有全局错误处理程序,则它优先于在 customErrors配置元素的 defaultRedirect 属性中指定的错误处理。
若要在页中创建全局处理程序,请创建 TemplateControl..::.Error 事件的处理程序。若要创建应用程序范围的错误处理程序,请在 Global.asax 文件中将代码添加到 HttpApplication..::.Error 事件。只要您的页或应用程序中发生未处理的异常,就会相应地调用这些方法。您可以从GetLastError 方法获取有关最新错误的信息。
下面的代码示例显示一个处理程序,它获取有关当前错误的信息,将其放在Session变量中,然后调用可以提取和显示错误信息的一般性错误处理页。
protected void Application_Error(Object sender, EventArgs e) { Session["CurrentError"] = "Global: " + Server.GetLastError().Message; Server.Transfer("lasterr.aspx"); }
本代码示例中的文件如下:
-
Web.config
-
Global.asax
-
Default.aspx
-
ExceptionUtility(要放在 App_Code 文件夹中)
-
GenericErrorPage.aspx
-
HttpErrorPage.aspx
msdn上的例子:本代码示例包括页级和应用程序级异常处理元素: 下载
引发错误的页面index.aspx
protected void Submit_Click(object sender, EventArgs e) { string arg = ((Button)sender).CommandArgument; if (arg.Equals("1")) { // Exception handled on the Generic Error Page throw new InvalidOperationException("Invalid click operation?!"); } else if (arg.Equals("2")) { // Exception handled on the current page throw new ArgumentOutOfRangeException("click?!"); } else { // Exception handled on the Http Error Page (per Web.Config) throw new Exception("Generic click problem?!"); } } private void Page_Error(object sender, EventArgs e) { // Get last error from the server Exception exc = Server.GetLastError(); // Filter for a specific kind of exception if (exc is ArgumentOutOfRangeException) { // Give the user some information, but // stay on the index page Response.Write("<h2>index Page Error</h2>\n"); Response.Write( "<p>ArgumentOutOfRange: Your click must have " + "been out of range?!</p>\n"); Response.Write("Return to the <a href='index.aspx'>" + "index Page</a>\n"); // Log the exception and notify system operators ExceptionUtility.LogException(exc, "indexPage"); ExceptionUtility.NotifySystemOps(exc); // Clear the error from the server Server.ClearError(); } // Filter for other kinds of exceptions else if (exc is InvalidOperationException) { // Pass the error on to the Generic Error page Server.Transfer("GenericErrorPage.aspx", true); } else { // Pass the error on to the index global handler } }
显示错误信息的页面
Request.IsLocal这个为true就是本地 为false就是用户
protected Exception ex = null; protected void Page_Load(object sender, EventArgs e) { // Get the last error from the server Exception ex = Server.GetLastError(); // Create a safe message string safeMsg = "A problem has occurred in the web site. "; // Show Inner Exception fields for local access if (ex.InnerException != null) { innerTrace.Text = ex.InnerException.StackTrace; InnerErrorPanel.Visible = Request.IsLocal; innerMessage.Text = ex.InnerException.Message; } // Show Trace for local access if (Request.IsLocal) exTrace.Visible = true; else ex = new Exception(safeMsg, ex); // Fill the page fields exMessage.Text = ex.Message; exTrace.Text = ex.StackTrace; // Log the exception and notify system operators ExceptionUtility.LogException(ex, "Generic Error Page"); ExceptionUtility.NotifySystemOps(ex); // Clear the error from the server Server.ClearError(); }
错误记录写入本地txt文件
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.IO; /// <summary> ///ExceptionUtility 的摘要说明 /// </summary> // Create our own utility for exceptions public sealed class ExceptionUtility { // All methods are static, so this can be private private ExceptionUtility() { } // Log an Exception public static void LogException(Exception exc, string source) { // Include enterprise logic for logging exceptions // Get the absolute path to the log file string logFile = "App_Data/ErrorLog.txt"; logFile = HttpContext.Current.Server.MapPath(logFile); // Open the log file for append and write the log StreamWriter sw = new StreamWriter(logFile, true); sw.Write("******************** " + DateTime.Now); sw.WriteLine(" ********************"); if (exc.InnerException != null) { sw.Write("Inner Exception Type: "); sw.WriteLine(exc.InnerException.GetType().ToString()); sw.Write("Inner Exception: "); sw.WriteLine(exc.InnerException.Message); sw.Write("Inner Source: "); sw.WriteLine(exc.InnerException.Source); if (exc.InnerException.StackTrace != null) sw.WriteLine("Inner Stack Trace: "); sw.WriteLine(exc.InnerException.StackTrace); } sw.Write("Exception Type: "); sw.WriteLine(exc.GetType().ToString()); sw.WriteLine("Exception: " + exc.Message); sw.WriteLine("Source: " + source); sw.WriteLine("Stack Trace: "); if (exc.StackTrace != null) sw.WriteLine(exc.StackTrace); sw.WriteLine(); sw.Close(); } // Notify System Operators about an exception public static void NotifySystemOps(Exception exc) { // Include code for notifying IT system operators } }
global.aspx
void Application_Error(object sender, EventArgs e) { //在出现未处理的错误时运行的代码 // Code that runs when an unhandled error occurs // Give the user some information, but // stay on the index page Exception exc = Server.GetLastError(); Response.Write("<h2>Global Page Error</h2>\n"); Response.Write( "<p>" + exc.Message + "</p>\n"); Response.Write("Return to the <a href='index.aspx'>" + "index Page</a>\n"); // Log the exception and notify system operators ExceptionUtility.LogException(exc, "indexPage"); ExceptionUtility.NotifySystemOps(exc); // Clear the error from the server Server.ClearError(); }
httperrorpage.aspx
<%@ Page Language="C#" %> <script runat="server"> protected HttpException ex = null; protected void Page_Load(object sender, EventArgs e) { ex = (HttpException)Server.GetLastError(); string safeMsg = String.Empty; // Filter for Error Codes and set text if (ex.ErrorCode >= 400 && ex.ErrorCode < 500) { ex = new HttpException (ex.ErrorCode, "Your file could not be found or " + "there was an access problem.", ex); } else if (ex.ErrorCode > 499) ex = new HttpException (ex.ErrorCode, "There was an error on the server.", ex); else ex = new HttpException (ex.ErrorCode, "There was a problem " + "with the web site.", ex); // Log the exception and notify system operators ExceptionUtility.LogException(ex, "HttpErrorPage"); ExceptionUtility.NotifySystemOps(ex); // Fill the page fields exMessage.Text = ex.Message; exTrace.Text = ex.StackTrace; // Show Inner Exception fields for local access if (ex.InnerException != null) { innerTrace.Text = ex.InnerException.StackTrace; InnerErrorPanel.Visible = Request.IsLocal; innerMessage.Text = ex.InnerException.Message; } // Show Trace for local access exTrace.Visible = Request.IsLocal; // Clear the error from the server Server.ClearError(); } </script> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head id="Head1" runat="server"> <title>Generic Error Page</title> </head> <body> <form id="form1" runat="server"> <div> <h2>Http Error Page</h2> <asp:Panel ID="InnerErrorPanel" runat="server" Visible="false"> <asp:Label ID="innerMessage" runat="server" Font-Bold="true" Font-Size="Large" /><br /> <pre> <asp:Label ID="innerTrace" runat="server" /> </pre> </asp:Panel> Error Message:<br /> <asp:Label ID="exMessage" runat="server" Font-Bold="true" Font-Size="Large" /> <pre> <asp:Label ID="exTrace" runat="server" visible="false" /> </pre> </div> </form> </body> </html>
web.config
<customErrors mode="RemoteOnly" defaultRedirect="HttpErrorPage.aspx"> </customErrors >