LINQ - 對付 SQL Injection 的 免費補洞策略 (转)

LINQ - 對付 SQL Injection 的 "免費補洞策略"

LINQ - 對付 SQL Injection 的 "免費補洞策略"

作者:黃忠成

一連串的 Mass SQL Injection 攻擊,讓我們回憶起數年前的 SQL Injection 攻擊,多年後的今天,我們仍深陷於同樣的危機中,本文詳述 SQL Injection 的歷史、肇因、解決及偵測方法,更為讀者們引介全新、更加安全的防堵 SQL Injection 策略。

什麼是 SQL Injection?

SQL Injection,中譯為 SQL 注入,更為人知的名稱是【資料隱碼攻擊】,意指開發人員於撰寫網頁應用程式之際,貪圖一時方便或是依循前人的慣性寫法而開啟的一道門。在數年前,一次大型的隱碼攻擊行動,喚起了所有網站擁有者及設計人員的防駭之心,讓我們認知到,網站是一個曝露在所有人面前的公共園地,其安全性不容忽視!在那次的攻擊行動中,有數千個網站遭到同一種手法入侵,洩露的資料及因入侵所損失的金額難以估計,而起源竟只是程式設計師的慣性及疏於防範,而我們都曾經是其中一份子。

那具體上,什麼是 SQL Injection 呢?其實說穿了很簡單,就是透過網頁上的輸入區域 (INPUT 如文字輸入框,或是 URL 中的查詢字串),將特定的 SQL 語句透過網頁送往資料庫執行。以一個登入網頁為例,在設計登入網頁時,我們會放兩個 TextBox 控件,分別讓使用者填入使用者 ID 及密碼,類似畫面如下:

圖 1:

在使用者按下登入按鈕後,我們將其輸入的資訊送往資料庫,驗證使用者輸入的登入資訊是否正確:

using System;
using System.Configuration;
using System.Data;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Data.SqlClient;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
if (ValidateUser(TextBox1.Text, TextBox2.Text))
Label1.Text = "歡迎你";
else
Label1.Text = "登入失敗";
}
private bool ValidateUser(string userName, string password)
{
SqlConnection conn = new SqlConnection(
"Data Source=JEFFRAY;Initial Catalog=Northwind;Integrated Security=True");
using (conn)
{
SqlCommand cmd = new SqlCommand("SELECT COUNT(*) FROM USERS WHERE USER_ID = '"
+ userName + "' AND PASSWORD = '" + password + "'", conn);
conn.Open();
return ((int)cmd.ExecuteScalar() > 0);
}
}
}

當你寫下這些程式碼時,已經開啟了 SQL Injection 的大門了,只要使用者於登入時,填入下圖的資訊,那麼不管 ID 密碼是什麼,一律可以登入系統。

圖 2:

這是為什麼呢?很簡單,起因於下面這行程式碼:

SqlCommand cmd = new SqlCommand("SELECT COUNT(*) FROM USERS WHERE USER_ID = '"
+ userName + "' AND PASSWORD = '" + password + "'", conn);

我們使用傳統 ASP 常見的手法,以組裝 SQL 指令的方式,將使用者的輸入融入既定的 SQL 語句中,但卻忽略了一件重要的事:使用者可以輸入任意的字串,包括了部份的 SQL 指令!透過輸入部份的 SQL 指令及微調,使用者可以輕易的改變這段 SQL 指令,甚至是疊加另一串 SQL 指令,而我們的網頁則照單全收,以上的輸入,會將整句 SQL 語句調整成下面這樣:

圖 3:

透過必然成真的條件式,再加上 SQL 的註解,我們的網站就這樣曝露在網路上,今天我加的是 OR,若是狠一點的加上 DROP TABLE 等破壞性指令,網站就此拜拜。

這種攻擊不僅僅出現在上例這種 POST 狀況,另一種 GET 狀態也常常受到同樣的攻擊,例如下面的程式碼即開啟了 SQL Injection 的大門。

using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Data.SqlClient;
public partial class QueryStringInjection : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
SqlConnection conn = new SqlConnection("Data Source=JEFFRAY;Initial Catalog=Northwind;Integrated Security=True");
using (conn)
{
SqlCommand cmd = new SqlCommand(
"SELECT * FROM Customers WHERE CustomerID = '"+Request.QueryString["ID"]+"'", conn);
conn.Open();
DetailsView1.DataSource =
cmd.ExecuteReader(CommandBehavior.CloseConnection);
DetailsView1.DataBind();
}
}
}
}

試著在 URL 上鍵入:

http://localhost:43236/FirstInjection/QueryStringInjection.aspx?ID=VINET' OR 1=1 --
註:http://localhost:43236 是你的 Web Development Server 自動產生的 Port,你必須視情況修改。

結果你會看到 CustomerID="VINET" 以外的 ALFKI 資料列,如下圖:

圖 4:

如果有心人士在 URL 上鍵入 DROP TABLE 或是 INSERT 的 QueryString,將資料任意的刪除或插入惡意的連結 Script (詳見後述的 Mass SQL Injection 一節),那後果不堪設想。

未啟用 Custom Error Page 的漏洞

你應該已經知道,寫 ASP.NET 應用程式的第一道安全手續就是啟用 Custom Error Page 功能,讓駭客們無法透過預設的錯誤網頁來取得不該取得的資訊,若未啟用 Custom Error Page,那麼下圖是可能發生在你的網站中的:

圖 5:

有了這些資訊,具有耐心的駭客,要透過輸入不同的字元來探測整段 SQL 語句就不困難了,防堵的最佳辦法就是啟用 Custom Error Page 設定:

Web.config
...............略<customErrors mode="On" defaultRedirect="DefaultError.htm"></customErrors>............略

一旦啟用後,錯誤發生時會導向 DefaultError.html,結果變成下面這樣:

圖 6:

檢測你的網頁有無 SQL Injection 的可能性

OK,那有沒有辦法可以檢測現在的網頁是否受 SQL Injection 威脅呢?如果你是網站管理者,而非設計師,那麼你只有依賴現在常見的網頁漏洞檢測工具,對網頁進行黑箱測試,不過提醒你,目前的網頁漏洞測試工具大多是針對 PHP、ASP 所設計的,能測出來的漏洞相當有限,有時即使是安全的網頁,也會因為未實作過濾法(後述),而導致誤判。

如果你是程式設計師,事情就簡單的多了,只要檢視一下程式碼,看看動態組裝 SQL 語句的部份是否有 SQL Injection 即可,圖 007 是一個確認 SQL Injection 是否存在於你的程式中的公式。

圖 7:

只要你的程式中,有 SQL 字串加上使用者輸入值的情況,那麼該網頁存在 SQL Injection 危機的可能性就高達 99.9%。

前輩的叮嚀:防止 SQL Injection 的方法

在數千個網站的入侵事件發生後,許多資安專家提出了各種防範 SQL Injection 的方法,其中不外乎圖 008 的四種。

圖 8:

過濾法可以阻止特定字如【--】、【 OR 】、【'】的輸入,能有效防堵必然成真條件式及錯誤訊息顯示時的漏洞,不過魔高一丈,此法最後仍然遭受破解,透過 SQL 的轉碼函式,駭客可以將部份 SQL 語句做出編碼來逃避偵測,最後突破這道防線。但由於轉碼後的字串相當長,所以只要設計師細心些,搭配 MaxLength 的設定,還是可以讓過濾法奏效,但過濾法其實很脆弱,所以一定要搭配其它的手法方能行之。

下面是一個使用過濾法的例子,利用引入外部 JavaScript 檔案及 Form 的 onSubmit 事件,在送出資料前先檢測擁有 ci Attribute 標示的 text tag,此法可運行於 IE 及 FireFox 上:

Injectiondetect.js

function validateInjection()
{
var i = 0;
for(i = 0; i < document.forms[0].elements.length;i++)
{
if(document.forms[0].elements[i].type == 'text' &&
document.forms[0].elements[i].getAttribute("ci") != null)
{
var elem = document.forms[0].elements[i];
if(elem.value != null &&
(elem.value.indexOf('\'') != -1 ||
elem.value.indexOf('--') != -1 ||
elem.value.indexOf(' OR ') != -1))
{
alert('possible injection detected.')
return false;
}
}
}
return true;
}

.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="DefaultWithFilter.aspx.cs" Inherits="DefaultWithFilter" %>
<!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 runat="server">
<title>Untitled Page</title>
<script language='javascript' type="text/javascript" src='injectiondetect.js'>
</script>
</head>
<body>
<form id="form1" οnsubmit="return validateInjection()" runat="server">
<div>
<table border="1">
<tr>
<td>使用者編號</td>
<td><asp:TextBox ID="TextBox1" ci="true" MaxLength="12"
runat="server"></asp:TextBox></td>
</tr>
<tr>
<td>密碼</td>
<td><asp:TextBox ID="TextBox2" ci="true" MaxLength="12"
runat="server"></asp:TextBox></td>
</tr>
<tr>
<td colspan=2>
<asp:Button ID="Button1" runat="server" Text="登入" οnclick="Button1_Click" />
</td>
</tr>
</table>
<asp:Label ID="Label1" runat="server" Text=""></asp:Label>
</div>
</form>
</body>
</html>

下圖是嘗試於此網頁進行 SQL Injection 攻擊時的結果:

圖 9:

不過,這種過濾法還不完善,因為資深的駭客仍然可以透過將網頁存成 HTML,移除 JavaScript 認證並假造 ViewState 來對網站進行 SQL Injection 攻擊!所以,完善的過濾法應該是 Client 端與 Server 都有,Server 端如下所示:

.aspx.cs

using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Data.SqlClient;
public partial class DefaultWithFilter : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
private bool DetectInjection(string input)
{
if (input.IndexOf("'") != -1 ||
input.IndexOf("--") != -1 ||
input.IndexOf(" OR ") != -1)
return true;
return false;
}
protected void Button1_Click(object sender, EventArgs e)
{
if (TextBox1.Text.Length > 12 ||
TextBox2.Text.Length > 12 ||
DetectInjection(TextBox1.Text) ||
DetectInjection(TextBox2.Text))
{
ClientScript.RegisterStartupScript(typeof(Page), "Alert_Msg",
"alert('possible injection detected.')", true);
return;
}
if (ValidateUser(TextBox1.Text, TextBox2.Text))
Label1.Text = "歡迎你";
else
Label1.Text = "登入失敗";
}
private bool ValidateUser(string userName, string password)
{
SqlConnection conn = new SqlConnection(
"Data Source=JEFFRAY;Initial Catalog=Northwind;Integrated Security=True");
using (conn)
{
SqlCommand cmd = new SqlCommand("SELECT COUNT(*) FROM USERS WHERE USERS.USER_ID = '"
+ userName + "' AND USERS.PASSWORD = '" + password + "'", conn);
conn.Open();
return ((int)cmd.ExecuteScalar() > 0);
}
}
}

或許你會覺得實作起來挺麻煩的,但這是過濾法所需付出的代價!

除了過濾法外,使用低權限的帳號連結資料庫也是安全常識之一,藉由降低連線帳號的權限,可以讓 DROP TABLE 等破壞力超強的手法碰壁,不過這種手法不應該成為唯一防堵 SQL Injection 的方式,因為你不可能連 INSERT 都不給執行,而 INSERT 是駭客入侵網頁的常見手法。

使用 Parameter 是目前已知,一勞永逸逃離 SQL Injection 的手法,將前述的程式調整成下面這樣,即可讓其完全逃離 SQL Injection。

using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Data.SqlClient;
public partial class Default2 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
if (ValidateUser(TextBox1.Text, TextBox2.Text))
Label1.Text = "歡迎你";
else
Label1.Text = "登入失敗";
}
private bool ValidateUser(string userName, string password)
{
SqlConnection conn = new SqlConnection(
"Data Source=JEFFRAY;Initial Catalog=Northwind;Integrated Security=True");
using (conn)
{
SqlCommand cmd = new SqlCommand(
"SELECT COUNT(*) FROM USERS WHERE USER_ID = @USER_ID AND PASSWORD = @PASSWORD", conn);
cmd.Parameters.AddWithValue("@USER_ID", userName);
cmd.Parameters.AddWithValue("@PASSWORD", password);
conn.Open();
return ((int)cmd.ExecuteScalar() > 0);
}
}
}

失效了嗎?這些方法

上節提及的幾種防堵 SQL Injection 的方法,在業界已經流傳許久,其中使用 Parameter 更是快變成常識級的考古用知識。那為何到目前為止,你仍然時常聽到某某網站遭受 SQL Injection 攻擊,甚至!你只要有足夠的時間及耐心,用 Google 以關鍵字【登入】、【資料查詢】查詢,接著以上述的【' OR 1=1 --】或是【'】來一一測試,輕輕鬆鬆就能找到幾個吃這套技巧的網站,然後取得極度敏感的個人資料或是其用來查詢的 SQL 字串。

SQL Injection 至今仍然存在的原因很簡單,程式設計師的惰性、慣性及大而化之的個性,是導致 SQL Injection 存在於這個高安全性當道時代的最大原因。

雖然使用 Parameter 手法可以防掉所有的 SQL Injection 攻擊,但在此同時,也增加了需要撰寫的程式碼長度,常見的結果便是設計師只會在特定敏感功能上,才會使用這種手法。

在現時今日,你很難當起駭客,透過 SQL Injection 手法通過極大多數網站的【登入】機制,原因不是程式設計師及網站管理者的細心,而是這個機制曾經出了個所有人都無法忽視的大包, 但 SQL Injection 只出現在這些機制上嗎?你我都知道,這不是真的,舉個實例來說,以下的查詢網頁是相當常見的。

圖 10:

這個網頁允許使用者任意輸入【公司名稱】、【客戶編號】、【聯絡人】等三個欄位之搜尋字串,然後進行組合查詢,如果使用者僅輸入【公司名稱】,那麼系統將不會把其它兩個欄位放入查詢語句中,請先閉上眼睛,思考著你怎麼實現這個功能,如果結果是下面這樣,那你已然開啟 SQL Injection 的大門了。

protected void Button1_Click(object sender, EventArgs e)
{
SqlConnection conn = new SqlConnection(
"Data Source=JEFFRAY;Initial Catalog=Northwind;Integrated Security=True");
using (conn)
{
SqlCommand cmd = new SqlCommand("SELECT * FROM Customers", conn);
string cmdStr = "";
if(TextBox1.Text.Length > 0)
cmdStr += string.Format(" CompanyName LIKE '%{0}%' AND ",TextBox1.Text);
if(TextBox2.Text.Length > 0)
cmdStr += string.Format(" CustomerID LIKE '%{0}%' AND ",TextBox2.Text);
if(TextBox3.Text.Length > 0)
cmdStr += string.Format(" ContactTitle LIKE '%{0}%' AND ",TextBox3.Text);
if (cmdStr.Length > 0)
cmd.CommandText += " WHERE " + cmdStr.Substring(0, cmdStr.Length - 5);
conn.Open();
GridView1.DataSource = cmd.ExecuteReader(CommandBehavior.CloseConnection);
GridView1.DataBind();
}
}

導致我們寫下這個程式的原因有三個:

圖 11:

第三個原因大概是寫下此程式之設計師真正的想法,那會變多長呢?我們試著寫一下就知道了。

protected void Button1_Click(object sender, EventArgs e)
{
SqlConnection conn = new SqlConnection(
"Data Source=JEFFRAY;Initial Catalog=Northwind;Integrated Security=True");
using (conn)
{
SqlCommand cmd = new SqlCommand("SELECT * FROM Customers", conn);
string cmdStr = "";
if (TextBox1.Text.Length > 0)
{
cmdStr += " CompanyName LIKE @CName AND ";
cmd.Parameters.AddWithValue("@CName", "%"+TextBox1.Text+"%");
}
if (TextBox2.Text.Length > 0)
{
cmdStr += " CustomerID LIKE @CID AND ";
cmd.Parameters.AddWithValue("@CID", "%" + TextBox2.Text + "%");
}
if (TextBox3.Text.Length > 0)
{
cmdStr += " ContactTitle LIKE @CTitle AND ";
cmd.Parameters.AddWithValue("@CTitle", "%" + TextBox3.Text + "%");
}
if (cmdStr.Length > 0)
cmd.CommandText += " WHERE " + cmdStr.Substring(0, cmdStr.Length - 5);
conn.Open();
GridView1.DataSource = cmd.ExecuteReader(CommandBehavior.CloseConnection);
GridView1.DataBind();
}
}

唔,也不是很長嘛,為了省幾行程式碼開這麼大的洞,值得嗎?呵,程式設計師就是這種動物,不是嗎?

補洞的代價

在你暗笑著,我怎麼可能會犯下前節的錯誤時,我必須提醒你程式設計師的第二個通病,那就是【以己度人】,白話就是【我不會犯的錯,所以別人也不會犯】,在群組開發時,這個情況更是履見不鮮。事實是,你不會寫下這段程式碼,但難保其它設計師不會,畢竟都是糊口飯吃的,只要補洞的工作需要付出時間代價,那麼就一定有人會偷懶或粗心,肇因可能是惰性、慣性,也可能是你未跟他明確提及這事兒的嚴重性,而後果常是我們無法承受的。

LINQ To SQL/LINQ To Entities = "免費的補洞策略"

除了程式設計師努力的防堵 SQL Injection 之外,開發平台廠商也沒有置身事外,以 Microsoft .NET 平台來說,為了防堵 SQL Injection,ASP.NET Team 於 ASP.NET 2.0 推出了 DataSource 控件群,這組控件利用了 Parameter 的手法,完全避開了 SQL Injection 的發生。但是我依舊時常聽到許多設計師抱怨:【DataSource 控件用起來綁手綁腳的,內部不知道在搞什麼,還不如自己用 SqlCommand 來得快且直覺。】,的確,事實是如此,DataSource 控件為了防堵 SQL Injection 所做的努力,換來的是【綁手綁腳】的惡名,這該歸咎於 ASP.NET Team 設計 DataSource 控件時,沒有多花點心思在易用性、安全性、彈性上取得平衡點。

終於,在 .NET Framework 3.5 及 Visual Studio 2008 上市後,兩個免費、快速、有效的補洞策略出現在我們眼前,他們就是【LINQ To SQL/LINQ To Entities】

說實話!這兩個技術都不是為了 SQL Injection 而誕生的,但其預設以 Parameter 手法運行的設計,卻給了我們一個新的防堵 SQL Injection 的方法,更好的是,程式設計師不但不用為了防堵 SQL Injection 寫更多的程式碼,相反的程式碼還變少了,以最初的登入機制為例,用 LINQ To SQL 改寫後變成下面這樣:

using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
public partial class LoginWithLINQ : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
NorthwindDataContext context = new NorthwindDataContext();
if( (from s1 in context.USERS where
s1.USER_ID == TextBox1.Text &&
s1.PASSWORD == TextBox2.Text select s1).Count() > 0)
Label1.Text = "歡迎你";
else
Label1.Text = "登入失敗";
}
}

由於 LINQ To SQL 會將 LINQ 運算式轉成 SQL 語句,然後將條件式一一以參數描述之故,透過 SQL Profiler 工具可得知,上面的程式最終送往 SQL Server 執行的語句如下:

exec sp_executesql N'SELECT COUNT(*) AS [value]
FROM [dbo].[USERS] AS [t0]
WHERE ([t0].[USER_ID] = @p0) AND ([t0].[PASSWORD] = @p1)',N'@p0 varchar(5),@p1 varchar(4)',@p0='admin',@p1='test'

很明顯的,這個技巧完全沒有 SQL Injection 的危機存在。

想加來加去,又不要 SQL Injection 嗎?LINQ 做給你

複合查詢常讓設計師不得不採用組裝式 SQL 語句手法,而其結果也常因為使用 Parameter 會導致程式碼變複雜,而循傳統手法完成該功能,最後留下 SQL Injection 的漏洞。那使用 LINQ To SQL/LINQ To Entities 來改寫的話,真的可以避免 SQL Injection 及簡化程式碼嗎?讓實例說話吧,我們以上例的複合查詢為例,改寫成 LINQ To SQL 版本之程式碼如下 :

protected void Button1_Click(object sender, EventArgs e)
{
NorthwindDataContext context = new NorthwindDataContext();
var baseData = from s1 in context.Customers select s1;
if(TextBox1.Text.Length > 0)
baseData = from s1 in baseData where
s1.CompanyName.Contains(TextBox1.Text) select s1;
if (TextBox2.Text.Length > 0)
baseData = from s1 in baseData where
s1.CustomerID.Contains(TextBox2.Text) select s1;
if (TextBox3.Text.Length > 0)
baseData = from s1 in baseData where
s1.ContactTitle.Contains(TextBox3.Text) select s1;
GridView1.DataSource = baseData;
GridView1.DataBind();
}

此例中,我利用了 LINQ To SQL/LINQ To Entities 只在列舉資料集元素前,才會開始組裝 SQL 語句的共通行為,以疊加式查詢的方式來完成複合查詢的工作,請特別注意,這段程式碼只會送出一段 SQL 語句,不是四個,透過 SQL Profiler 可以證明這點:

exec sp_executesql N'SELECT [t0].[CustomerID], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactTitle], [t0].[Address],
[t0].[City], [t0].[Region], [t0].[PostalCode], [t0].[Country], [t0].[Phone], [t0].[Fax], [t0].[NOTES], [t0].[TEST_ID]
FROM [dbo].[Customers] AS [t0]
WHERE ([t0].[CustomerID] LIKE @p0) AND ([t0].[CompanyName] LIKE @p1)',N'@p0 nvarchar(4),@p1 nvarchar(3)',@p0=N'%FR%',@p1=N'%V%'

讓事實說話:LINQ To SQL VS SQL Injection

我說你不一定信,你可以下載範例,然後對本文所提及的兩個 LINQ To SQL 網頁進行 SQL Injection 的測試,圖 012 是以【' OR 1=1 --】手法來測試登入機制:

圖 12:

圖 013 是複合查詢的測試:

圖 13:

改用 LINQ To Entities 也是一樣的結果。

幫幫忙,別自己開洞,ExecuteQuery 及 ExecuteCommand

那使用 LINQ To SQL/LINQ To Entities 就能保證不被 SQL Injection 所擾了嗎?那可不一定,因為設計師還是常常會貪一時方便,開啟 SQL Injection 的大門。基於彈性,LINQ To SQL 及 LINQ To Entities 都支援直接將 SQL 語句送往資料庫執行的機制,LINQ To SQL 的 ExecuteQuery 就是一個例子:

protected void Button1_Click(object sender, EventArgs e)
{
NorthwindDataContext context = new NorthwindDataContext();
string str = "SELECT * FROM USERS WHERE USER_ID = '" + TextBox1.Text +
"' AND PASSWORD = '" + TextBox2.Text + "'";
int ret = context.ExecuteQuery<USERS>(str).Count();
if (ret > 0)
Label1.Text = "歡迎你";
else
Label1.Text = "登入失敗";
}

所以,要防堵 SQL Injection,使用 LINQ To SQL/LINQ To Entities 是最具成效及具經濟效益的,不過前提是設計師得幫幫忙,別放著有新的方便且有效率的技巧不學,故意去當打洞工人。

迷思:Stored Procedure 是安全的,Parameter 是無敵的?

的確,是我告訴你,使用 Parameter 是防堵 SQL Injection 最快、最有效、最完整的手法,但是前題是不能與 Stored Procedure 扯上關係!基於網路上的片段資料,設計師總覺得,如果我使用了 Stored Procedure,並使用 Parameter 來傳遞參數,那就對 SQL Injection 完全免疫了!所有軟體專案主導者都同意,當要求不明確時,結果也會不明確,基於防堵 SQL Injection 的大前題下,許多專案主導者都會要求設計師不要在程式中組裝 SQL 語句,而改用 Stored Procedure,但!他們卻高估了程式設計師的的理解力,天才工程師以 Stored Procedure 來處理複合查詢,寫下程式碼如下:

protected void Button1_Click(object sender, EventArgs e)
{
SqlConnection conn = new SqlConnection(
"Data Source=JEFFRAY;Initial Catalog=Northwind;Integrated Security=True");
using (conn)
{
SqlCommand cmd = new SqlCommand("QueryCustomers", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@CompanyName",
TextBox1.Text.Length == 0 ? "" : TextBox1.Text);
cmd.Parameters.AddWithValue("@CustomerID",
TextBox2.Text.Length == 0 ? "" : TextBox2.Text);
cmd.Parameters.AddWithValue("@ContactTitle",
TextBox3.Text.Length == 0 ? "" : TextBox3.Text);
conn.Open();
GridView1.DataSource = cmd.ExecuteReader(CommandBehavior.CloseConnection);
GridView1.DataBind();
}
}

正如你所見,這是一段看不出問題在那的程式碼,直到看到了 QueryCustomers 的預存程序,你會吐血:

CREATE PROCEDURE dbo.QueryCustomers
(
@CompanyName nvarchar(30),
@CustomerID nvarchar(12),
@ContactTitle nvarchar(30)
)
AS
DECLARE @STR nvarchar(255)
DECLARE @WK nvarchar(255)
SET @STR = 'SELECT * FROM Customers'
SET @WK = ''
IF NOT @CompanyName IS NULL
SET @WK = @WK + ' CompanyName LIKE ''%'+@CompanyName+'%'' AND  '
IF NOT @CustomerID IS NULL
SET @WK = @WK + ' CustomerID LIKE ''%'+@CustomerID+'%'' AND  '
IF NOT @ContactTitle IS NULL
SET @WK = @WK + ' ContactTitle LIKE ''%'+@ContactTitle+'%'' AND  '
IF LEN(@STR) > 0
BEGIN
SET @STR = @STR+' WHERE '+SUBSTRING(@WK,0,LEN(@WK)-3)
exec sp_executesql @STR
End
ELSE
exec sp_executesql @STR

結果就是:

圖 14:

一旦變成這樣,就算是 LINQ To SQL/LINQ To Entities 也無法救你脫離 SQL Injection 的威脅!所以,你應該明確的告訴設計師,SQL Injection 是由組裝式 SQL 語句而引發的,得注意任何有【組裝式 SQL】發生的程式碼,這當然也包含了 Stored Procedure。此例正確的 Stored Procedure 寫法如下:

CREATE PROCEDURE dbo.SafeQueryCustomers
(
@CompanyName nvarchar(30),
@CustomerID nvarchar(12),
@ContactTitle nvarchar(30)
)
AS
DECLARE @STR nvarchar(255)
DECLARE @WK nvarchar(255)
SET @STR = 'SELECT * FROM Customers'
SET @WK = ''
IF NOT @CompanyName IS NULL
BEGIN
SET @WK = @WK + ' CompanyName LIKE @pCompanyName AND  '
SET @CompanyName = '%' +@CompanyName + '%'
END
IF NOT @CustomerID IS NULL
BEGIN
SET @WK = @WK + ' CustomerID LIKE @pCustomerID AND  '
SET @CustomerID = '%' +@CustomerID + '%'
END
IF NOT @ContactTitle IS NULL
BEGIN
SET @WK = @WK + ' ContactTitle LIKE @pContactTitle AND  '
SET @ContactTitle = '%' +@ContactTitle + '%'
END
IF LEN(@STR) > 0
BEGIN
SET @STR = @STR+' WHERE '+SUBSTRING(@WK,0,LEN(@WK)-3)
exec sp_executesql @STR,
N'@pCompanyName nvarchar(30),@pCustomerID nvarchar(12),@pContactTitle nvarchar(30)',
@pCompanyName=@CompanyName,@pCustomerID=@CustomerID,@pContactTitle=@ContactTitle
End
ELSE
exec sp_executesql @STR

使用參數是防堵 SQL Injection 的不二法門,就算是在 Stored Procedure 中亦是如此。

魔高一丈:新一代的 Mass SQL Injection 手法

網頁的攻擊威脅中,SQL Injection 算是相當狠毒的手法,因為破壞性高,所以也就更引人注目,但 SQL Injection 是一種手法的統稱,近日各大報的報導,相信大多人都已見識到新一代的 SQL Injection 手法,統稱為【Mass SQL Injection】

此手法是利用了傳統的 SQL Injection 為進入點,再利用設計師對於控件行為的熟悉度不足,及忽視網頁安全性來侵入。舉個例來說,我們常用 GridView 等控件來顯示資料,為了某些理由,我們會直接以方式來輸出列資料,如下所示:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="InputInjection.aspx.cs" Inherits="InputInjection" %>
<!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 runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:LinqDataSource ID="LinqDataSource1" runat="server"
ContextTypeName="NorthwindDataContext"
Select="new (CustomerID, CompanyName, NOTES)" TableName="Customers">
</asp:LinqDataSource>
<asp:GridView ID="GridView1" runat="server" AllowPaging="True"
AutoGenerateColumns="False" DataSourceID="LinqDataSource1">
<Columns>
<asp:BoundField DataField="CustomerID"
HeaderText="CustomerID" ReadOnly="True"
SortExpression="CustomerID" />
<asp:BoundField DataField="CompanyName" HeaderText="CompanyName"
ReadOnly="True" SortExpression="CompanyName" />
<asp:TemplateField HeaderText="NOTES" SortExpression="NOTES">
<EditItemTemplate>
<asp:Label ID="Label1" runat="server"
Text='<%# Eval("NOTES") %>'></asp:Label>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label1" runat="server"
Text='<%# Eval("NOTES") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
</form>
</body>
</html>

很平常的程式碼不是,結果也很平常:

圖 15:

直到你在第一筆資料的 NOTES 欄位中鍵入下面的文字:

<script>alert('test')</script>

結果將會有所改變:

圖 16:

歡迎來到 Mass SQL Injection 的世界,Mass SQL Injection 利用了設計師常忽略了輸出資料時要使用 Html Encode 機制的常識,而進行了非毀滅性的入侵,這種入侵常見於討論區、部落格或留言版上,他的目的並非毀滅此網站,而只是利用此漏洞來當掉此網站,亦或是將此網站做為跳板,以 Cross-Site Scripting (簡稱為 XSS) 的方式,將使用者所輸入的資料,導向另一網站,而這個網站通常是駭客們所建構的,無辜瀏覽此網站的人所輸入的資料就這樣被偷走了。

另一種更狠毒的手法則是利用 Cross-Site Scripting 的方式,在網頁中注入惡意連結的 Script,透過作業系統的漏洞如 Windows 的 MS06-014、MS07-004 來入侵使用者的電腦,將網站當成跳板是第一步,接著再把瀏覽器當成第二跳版,最後入侵使用者的電腦。

當然,你可能會說,我常用的是 Bind,不是 Eval 這個函式,那麼我告訴你,這兩者有同樣的問題存在。就算不用到 Eval 或是 Bind,你偶而也會寫成下面這樣子:

.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="InputInjection.aspx.cs" Inherits="InputInjection" %>
<!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 runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<div><%=GetDynamicHtml() %></div>
..........略..........
</div>
</form>
</body>
</html>

.aspx.cs

protected string GetDynamicHtml()
{
string str = "<b>TEST Injection</b>";
return str;
}

想像一下,如果 GetDynamicHtml 函式中的 str 變數值是由資料庫取得後填入的,你是否有背脊發涼的感覺了。

如何防止?

防堵 Mass SQL Injection 的方法其實很簡單,除了以 Parameter 或是 LINQ To SQL/LINQ To Entities 來阻檔傳統的 SQL Injection 攻擊外,只要在輸出資料庫資料時,記得用 HtmlEncode 即可:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="InputInjection.aspx.cs" Inherits="InputInjection" %>
<!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 runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:LinqDataSource ID="LinqDataSource1" runat="server"
ContextTypeName="NorthwindDataContext"
Select="new (CustomerID, CompanyName, NOTES)" TableName="Customers">
</asp:LinqDataSource>
<asp:GridView ID="GridView1" runat="server" AllowPaging="True"
AutoGenerateColumns="False" DataSourceID="LinqDataSource1">
<Columns>
<asp:BoundField DataField="CustomerID"
HeaderText="CustomerID" ReadOnly="True"
SortExpression="CustomerID" />
<asp:BoundField DataField="CompanyName" HeaderText="CompanyName"
ReadOnly="True" SortExpression="CompanyName" />
<asp:TemplateField HeaderText="NOTES" SortExpression="NOTES">
<EditItemTemplate>
<asp:Label ID="Label1" runat="server"
Text='<%# Eval("NOTES") %>'></asp:Label>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text=
'<%# Server.HtmlEncode(Eval("NOTES") == null ? "" : Eval("NOTES").ToString()) %>'>
</asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
</form>
</body>
</html>

圖 17:

那如果執意輸出 HTML 呢?那我只能建議你,在輸出前查查輸出的字串中是否有 script 字樣,並注意 onclick、onkeydown、onblur 等事件及 src tag 的輸出,沒有必要的話,就把所有的事件處理式濾掉,這樣才能讓你逃出 Mass SQL Injection 的攻擊,下面是一個簡單的例子,允許除 script 外的 HTML 輸出。

.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="InputInjection2.aspx.cs" Inherits="InputInjection2" %>
<!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 runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:LinqDataSource ID="LinqDataSource1" runat="server"
ContextTypeName="NorthwindDataContext"
Select="new (CustomerID, CompanyName, NOTES)" TableName="Customers">
</asp:LinqDataSource>
<asp:GridView ID="GridView1" runat="server" AllowPaging="True"
AutoGenerateColumns="False" DataSourceID="LinqDataSource1">
<Columns>
<asp:BoundField DataField="CustomerID"
HeaderText="CustomerID" ReadOnly="True"
SortExpression="CustomerID" />
<asp:BoundField DataField="CompanyName" HeaderText="CompanyName"
ReadOnly="True" SortExpression="CompanyName" />
<asp:TemplateField HeaderText="NOTES" SortExpression="NOTES">
<EditItemTemplate>
<asp:Label ID="Label1" runat="server"
Text='<%# Eval("NOTES") %>'></asp:Label>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label1" runat="server"
Text='<%# GetSafeHtml(Eval("NOTES")) %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
</form>
</body>
</html>

.aspx.cs

using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
public partial class InputInjection2 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected string GetSafeHtml(object o)
{
if (o != null)
{
string o2 = (string)o;
if (o2.IndexOf("<script",StringComparison.InvariantCultureIgnoreCase) != -1)
{
while (true)
{
int index = o2.IndexOf("<script",
StringComparison.InvariantCultureIgnoreCase);
if (index == -1) break;
o2 = o2.Replace(o2.Substring(index, 8), "<!-- ");
index = o2.IndexOf("</script>",
StringComparison.InvariantCultureIgnoreCase);
o2 = o2.Replace(o2.Substring(index, 9), " !-->");
}
}
return o2;
}
return string.Empty;
}}

當 NOTES 值為【<b>test</b>】時,輸出結果如下:

圖 18:

GetSafeHtml 也適用於前例的 GetDynamicHtml 情況下:

<div><%=GetSafeHtml(GetDynamicHtml()) %></div>

關於 validateRequest

或許你會好奇,ASP.NET 1.1 其之後的版本不是有一個 validateRequest 設定,只要其值為 True,那麼使用者所輸入的值,將會受到 ASP.NET 的限制 (TextBox、及 URL 後帶的參數都在此限),而此值預設為 True,意味著如果你沒有特別去修改 mechine.config 或是 web.config 將此值設為 False,使用者是無法於 TextBox 控件或是 URL 參數中輸入【<script>alert('test')</script】等字樣的,那也就沒有 Mass SQL Injection 危機了不是嗎?

Web.config

<system.web>
............
<pages buffer="true" validateRequest="true" />
............
</system.web>

圖 19:

的確,但這樣一來,連【<b>TEST</b>】等輸入也一併被防掉了,在許多討論區及留言版中,這種輸入是必要的!況且,ASP.NET 1.x 在 validateRequest 的驗證上有著 BUG,若你未更新 ASP.NET 2.0 或是最新的 ASP.NET 1.x Service Pack,那麼 Mass SQL Injection 仍然與你長伴。

那如果用的已是 ASP.NET 2.0,且更新到最新版並將 validateRequest 設為 Ture 後,是否就可高枕無憂了呢?這我不能保證,因為在BUG未被發現前,都不叫 BUG!而且在這個 AJAX 盛行的年代,以 XMLHttpRequest 穿透 Validate Request 機制並不是不可能。所以,validateRequest 絕不能做為防止 Mass SQL Injection 的唯一手段,應整合 SQL Injection 的所有防範手段,至少必須使用 Parameter 或是 LINQ To SQL/LINQ To Entities 來與資料庫溝通,才是正道。

後記

因為網頁是隨手可得,所以成為了駭客們的玩具,本文所提及的僅是關於 SQL Injection 的手法,其它如 DDoS 等攻擊還是很多,身為網頁設計師的我們,除了必須細心之外,還得時常上一些安全性回報網站來擷取新知,對於駭客,我們必須常保初學者心態,因為駭客們就是抓住程式設計師自持身經百戰的傲氣,而趁虛而入。

範例解說:

檔名說明
Default.aspx無設防之 Login 網頁 (有 SQL Injection 危機)。
Default2.aspx設防之 Login 網頁 (使用參數,無 SQL Injection 危機)。
DefaultWithFilter.aspx設防之 Login 網頁,使用過濾法。
QueryStringInjection.aspx無設防之 QueryString 網頁(有 SQL Injection 危機)。
InputInjection.aspxMass SQL Injection 測試網頁 (已設防,請自行調整為不設防來測試),使用LINQ To SQL。
InputInjection2.aspxMass SQL Injection 測試網頁 2 (已設防,採用過濾 script 手法) ,使用 LINQ To SQL。
QueryData.aspx簡單資料查詢頁面 (無設防,有 SQL Injection 危機)。
QueryData2.aspx簡單資料查詢頁面 (已設防,使用參數,無 SQL Injection 危機)。
QueryData3.aspx複合查詢頁面 (無設防,包含無設防及有設防之 Stored Procedure 手法)。
QueryData4.aspx複合查詢頁面 (已設防,無 SQL Injection 危機)。
LoginWithLINQ.aspx設防之 Login 網頁,使用 LINQ To SQL。
QueryData4WithLinq.aspx設防之複合查詢頁面,使用 LINQ To SQL。


http://www.microsoft.com/taiwan/msdn/columns/huang_jhong_cheng/LVSS.htm

转载于:https://www.cnblogs.com/yhb199/archive/2008/07/11/1240557.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/411665.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Visual Studio .Net团队开发[转]

一、 开发前的准备1、 在装有Windows 2000或者Windows XP Professional的机器上安装.net Framework SDK、Visual Studio.Net、Visual Source Safe 6C。&#xff08;如果用户操作系统是Windows .Net Server&#xff0c;则无须安装.Net Framework SDK&#xff0c;.Net Server自带…

mysql数据库root密码在哪个文件中_mysql - 本地数据库忘记了root用户的密码

在连接本地mysql数据库一直都是客户端保存密码&#xff0c;然后一键登录。突然开发要用到这个数据库时&#xff0c;脑子嗡嗡的了……忘记了密码&#xff0c;试了很多遍还是记不起来。没办法只能去找方案了&#xff0c;网上还是有很多跟我一样的大佬的。这里记录下&#xff0c;省…

Inside IronPython: IronPython AST语法树(2/2)

接上篇: Inside IronPython: IronPython AST语法树(1/2) ASTs简介&#xff1a; 当 ipy.exe 执行demo.py的时候&#xff0c;IronPython语言自身的实现和DLR共同参与源代码的编译处理。从基本层面上来讲&#xff0c;编译器是流水化作业的&#xff1a;从语法解析器生成描述源代码…

如何开通支付宝

一、登录支付宝网站注册&#xff1a; 1、注册支付宝账户 1&#xff09;进入支付宝网站https://www.alipay.com/点击“免费注册”按钮 进入支付宝网站https://www.alipay.com/&#xff0c;如果图片有不显示的&#xff0c;请刷新一下&#xff0c;或者将鼠标放到红叉的位置&#x…

mysql的aborted_mysql参数:aborted_connects过大

mysql参数&#xff1a;aborted_connects过大(2015-12-31 11:32:08)标签&#xff1a;mysql运维it如果一个客户端在成功连接之后&#xff0c;不正常中断或结束&#xff0c;Aborted_connects将会增加1&#xff0c;并会将日志记录到error日志里。(log_warning设置为2才会记录)原因可…

小白学docker(1)---docker安装

最近学习下docker&#xff0c;并且工作需要&#xff0c;就总结下。 1、Docker安装 a、先查看下CentOS版本 b、查看下Linux内核版本 c、执行wget -qO- https://get.docker.com/|sh 其实就是一个执行脚本来快速安装开发环境docker d、启动sudo systemctl docker start 执行命令确…

.NET平台依赖注入机制及IoC的设计与实现

我们设计的分层架构&#xff0c;层与层之间应该是松散耦合的。因为是单向单一调用&#xff0c;所以&#xff0c;这里的“松散耦合”实际是指上层类不能具体依赖于下层类&#xff0c;而应该依赖于下层提供的一个接口。这样&#xff0c;上层类不能直接实例化下层中的类&#xff0…

php嵌套查询mysql语句_mysql 查询嵌套

问题描述 为使讨论简单易懂&#xff0c;我将问题稍作简化&#xff0c;去掉诸多的背景。 从前有一个皇帝&#xff0c;他有50个妃子&#xff0c;这些妃子很没有天理的给他生了100,000个儿子&#xff0c;于是&#xff0c;皇帝很苦恼&#xff0c;海量的儿子很难管理&#xff0c;而且…

征途pak文件修改_传奇技能,第十四祭:装备属性修改与增加新装备

技能献祭&#xff0c;Get 新技能&#xff1a;传奇技能——应用篇&#xff0c;增加新装备与绑特效跟航家学技能&#xff0c;用正式服带你飞&#xff0c;底部有配套学习资源场景&#xff1a;游戏中装备的属性是可以修改的&#xff0c;基础攻防属性可以直接在物品数据库中修改&…

本题要求实现一个用选择法对整数数组进行简单排序的函数。_通俗易懂讲 Python 算法:快速排序...

原文&#xff1a;https://stackabuse.com/quicksort-in-python/作者&#xff1a;Marcus Sanatan译者&#xff1a;老齐欢迎在 bilibili 搜索 freeCodeCamp 官方账号或者直接访问 https://space.bilibili.com/335505768 观看我们的技术视频介绍快速排序是一种流行的排序算法&…

vscode标记_高效扩展工具让 VS Code 如虎添翼

Codelf 变量命名神器Star&#xff1a;10688https://github.com/unbug/codelf新建项目&#xff0c;变量&#xff0c;类&#xff0c;方法&#xff0c;接口都需要命名&#xff0c;一个好的命名可以一眼看出这个地方的功能&#xff0c;CodeIf 一键起名不再难&#xff0c;输入关键词…

CSS 有关Position = absolute (绝对定位 是相对于谁而言)

css中有绝对定位法&#xff0c;以前一直搞不懂绝对定位是相对于谁而言的绝对定位。 现在搞清楚了&#xff0c;不是相对于父元素&#xff0c;也不是相对于BODY。 而是相对于所属元素树中&#xff0c;相邻最近的那个显示标识了position属性的元素。 比如 Code<div id"a&q…

mysql gui vim_vim(一): 小技巧

1) 如何yank字符然后再查找 ( / Ctrl - R 0 ) The most recently yanked text will be stored in the 0 and registers (if no register was explicitly specified e.g. by xy ). Then you can paste the text of any that register in the last line (eith1) 如何yank字符然后…

LeetCode Smallest Range

数据范围是3500,3500也就是说n的平方是可以接受的。这里告诉你就是有序的,也就是在提醒你可能会是一个类似于二分的算法,所以的话其实基于这两个认识的话我们就可以利用一个枚举叫二分的算法来解决这道题。怎么做呢&#xff1f;就首先的话我们要枚举一端,一端的话我们可以把所有…

Web前端3.0时代,“程序猿”如何“渡劫升仙”

Web前端入行门槛低&#xff0c;很多人在成为前端工程师后很容易进入工作的舒适区&#xff0c;认为该熟悉的业务已熟悉了&#xff0c;然后就是重复用轮子&#xff0c;这样很容易让自己的成长处于原地打转以及低水平重复的状态。 想要不被行业抛弃&#xff0c;就要努力提升自己。…

mysql用 fifo 记录日志_MySQL一丢丢知识点的了解

1. MySQL体系结构从概念上讲&#xff0c;数据库是文件的集合&#xff0c;是依照某种数据模型组织起来并存放于二级存储器中的数据集合&#xff1b;数据库实例是程序&#xff0c;是位于用户与操作系统之间的一层数据管理软件&#xff0c;用户对数据库数据的任何操作&#xff0c;…

HttpHandler

概述HttpHandler是一个HTTP请求的真正处理中心&#xff0c;也正是在这个HttpHandler容器中&#xff0c;ASP.NET Framework才真正地对客户端请求的服务器页面做出编译和执行&#xff0c;并将处理过后的信息附加在HTTP请求信息流中再次返回到HttpModule中。 IHttpHandler是什么 I…

小程序云开发搜索功能的实现正则_码code | 如何借助小程序云开发实现小程序支付功能...

转载来源&#xff1a;编程小石头我们在做小程序支付相关的开发时&#xff0c;总会遇到这些难题。小程序调用微信支付时&#xff0c;必须要有自己的服务器&#xff0c;有自己的备案域名&#xff0c;有自己的后台开发。这就导致我们做小程序支付时的成本很大。本节就来教大家如何…

python接口自动化(二十五)--unittest断言——下(详解)

简介 本篇还是回归到我们最初始的话题&#xff0c;想必大家都忘记了&#xff0c;没关系看这里&#xff1a;传送门 没错最初的话题就是登录&#xff0c;由于博客园的登录机制改变了&#xff0c;本篇以我找到的开源免费的登录API为案例&#xff0c;结合 unittest 框架写 2 个用例…

mysql-bin磁盘满数据库重启不_liunx磁盘空间满了,导致mysql数据库无法启动

如何启动/遏制/重启MySQLA、1、启动圆式1、哄骗 service 启动&#xff1a;service mysqld start2、哄骗 mysqld 脚本启动&#xff1a;/etc/inint.d/mysqld start3、哄骗 safe_mysqld 启动&#xff1a;safe_mysqld&二、遏制1、哄骗 service 启动&#xff1a;service mysqld …