EC Council CASE.NET_Common Application-Level Attacks_lab1.SQL 注入攻擊跟防範
一個登入畫面程式
用
Username: tester1
Password: test1
成功登入
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 | using System; using System.Collections.Generic; using System.Configuration; using System.Data; using System.Data.SqlClient; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; namespace Labs.Module1.Lab1 { public partial class login : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { } protected void Btn_login_Click(object sender, EventArgs e) { string strcon = ConfigurationManager.ConnectionStrings["accounts"].ConnectionString; SqlConnection con = new SqlConnection(strcon); SqlCommand cmd = new SqlCommand ("SELECT [firstname],[lastname],[mobile],[email] FROM [accounts] where [uname]='" + UserName.Text + "' AND [password] = '" + txtpwd.Text + "'", con); SqlDataAdapter da = new SqlDataAdapter(cmd); DataSet ds = new DataSet(); try { da.Fill(ds); if (ds.Tables[0].Rows.Count > 0) { Response.Redirect("Index.aspx"); } else { Response.Redirect(Request.RawUrl); } } catch { ds = null; } } } } |
緊接著登出嘗試用SQL注入的攻擊手法來ByPass
Username: ' OR 1 = 1; --
Password: password
成功ByPass登入進來
甚至可以在SQL注入語法
去對方商業資料庫中產生table
' OR 1 = 1; CREATE TABLE XXXXXXX( CID int , NAME nvarchar(50));--
甚至drop db 或其他table等恐怖操作
' OR 1 = 1; --
' OR 1 = 1; CREATE TABLE XXXXXXX( CID int , NAME nvarchar(50));--
' OR 1 = 1 drop.... --;
防範方式
改為參數化
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 | using System; using System.Collections.Generic; using System.Configuration; using System.Data; using System.Data.SqlClient; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; namespace Labs.M1Lab1 { public partial class login : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { } protected void Btn_login_Click(object sender, EventArgs e) { string strcon = ConfigurationManager.ConnectionStrings["accounts"].ConnectionString; SqlConnection con = new SqlConnection(strcon); SqlCommand cmd = new SqlCommand ("SELECT [firstname],[lastname],[mobile],[email] FROM [accounts] where [uname]=@uname AND [password] = @pwd", con); SqlParameter uname = new SqlParameter("@uname", SqlDbType.VarChar); SqlParameter pwd = new SqlParameter("@pwd", SqlDbType.VarChar); uname.Value = UserName.Text; pwd.Value = txtpwd.Text; cmd.Parameters.Add(uname); cmd.Parameters.Add(pwd); SqlDataAdapter da = new SqlDataAdapter(cmd); DataSet ds = new DataSet(); try { da.Fill(ds); } catch { ds = null; } if (ds.Tables[0].Rows.Count > 0) { Response.Redirect("Index.aspx"); } else { Response.Redirect(Request.RawUrl); } } } } |
也可以改ORM或是寫成Store Procedure(SP寫法也要用參數化)
來看一個MVC的案例
檢視畫面的code
主要是去到Lab1控制器下的InSecureLogin動作方法
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 69 70 71 72 73 74 75 76 77 78 79 80 81 | <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title>eElectronics - HTML eCommerce Template</title> <!-- Custom CSS --> <link href="~/ViewCSS/css/bootstrap.min.css" rel="stylesheet" /> <link rel="stylesheet" href="~/ViewCSS/css/owl.carousel.css" /> <link rel="stylesheet" href="~/ViewCSS/style.css" /> <link rel="stylesheet" href="~/ViewCSS/css/responsive.css" /> </head> <body> <div id="intro1"> <div class="container"> <div class="wrapper"> <div class="form-signin"> <h3 class="form-signin-heading">Login</h3> <hr class="colorgraph"><br> <!--<span class="alert" id="lblerror" style="">Invalid Credentials</span>--> @model Labs.Models.account @{ //ViewBag.Title = "login"; //Layout = "~/Shared/Views/_ViewStart.cshtml"; } @using (Html.BeginForm("InSecureLogin", "Lab1")) { { @Html.ValidationSummary(true) { <fieldset> @Html.TextBoxFor(model => model.uname, new { placeholder = "User Name", @class = "form-control" }) @Html.ValidationMessageFor(model => model.uname) @Html.PasswordFor(Model => Model.password, new { placeholder = "Password", @class = "form-control" }) @Html.ValidationMessageFor(model => model.password) <input type="submit" value="login" /> @ViewBag.data </fieldset> } } } </div> </div> </div> </div> <!-- jQuery sticky menu --> <script src="~/ViewCSS/js/Jquery.min.js"></script> <script src="~/ViewCSS/js/bootstrap.min.js"></script> <script src="~/ViewCSS/js/owl.carousel.min.js"></script> <script src="~/ViewCSS/js/jquery.sticky.js"></script> <!-- jQuery easing --> <script src="~/ViewCSS/js/jquery.easing.1.3.min.js"></script> <!-- Main Script --> <script src="~/ViewCSS/js/main.js"></script> </body> </html> |
Lab1控制器的code
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 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | using System; using System.Collections.Generic; using System.Configuration; using System.Data.SqlClient; using System.Linq; using System.Web; using System.Web.Mvc; using Labs.Models; using System.Data; namespace Labs.Controllers { public class Lab1Controller : Controller { EntitiyConn db = new EntitiyConn(); public ActionResult Index() { return View(); } public ActionResult Login() { return View(); } [HttpPost] public ActionResult SecureLogin(account Mlog) { /* User_Login rs = new User_Login(); // var pass = from m in db.registers where m.emailid == li.Emailid select m.userpassword; var pass = from m in db.User_Login where m.Uname == Mlog.Uname && m.password == Mlog.password select m; if (pass.Count() > 0) return View("Index"); else return View("Login"); */ account rs = new account(); // var pass = from m in db.registers where m.emailid == li.Emailid select m.userpassword; var pass = from m in db.accounts where m.uname == Mlog.uname && m.password == Mlog.password select m; if (pass.Count() > 0) return View("Index"); else return View("Login"); } public ActionResult Logout() { return Redirect("Login"); } [HttpPost] public ActionResult InSecureLogin(account acc) { string strcon = ConfigurationManager.ConnectionStrings["SqlConn1"].ConnectionString; SqlConnection con = new SqlConnection(strcon); SqlCommand cmd = new SqlCommand ("SELECT [Uid],[firstname],[lastname],[mobile],[email]FROM [ECSPLabs].[dbo].[accounts] where [uname]='" + acc.uname + "' AND [password] = '" + acc.password + "'", con); SqlDataAdapter da = new SqlDataAdapter(cmd); DataSet ds = new DataSet(); try { da.Fill(ds); } catch { ds = null; } if (ds.Tables[0].Rows.Count > 0) { acc.uid = Convert.ToInt16(ds.Tables[0].Rows[0][0].ToString()); Session["UserId"] = ds.Tables[0].Rows[0][0]; return View("Index"); } else { return View("Login"); } } } } |
這邊一樣這種直接透過組字串方式是最危險的
Username: ' OR 1 = 1; --
Password: password
都能夠直接By Pass 登入的查檢
這邊我們改將表單打向SecureLogin的動作方法
把
@using (Html.BeginForm("InSecureLogin", "Lab1"))
取代為
@using (Html.BeginForm("SecureLogin", "Lab1"))
當我們執行時就會發現EF 基於ORM 機制
其實會自動將SQL注入危險給解決掉。
留言
張貼留言