نسخهٔ فعلی |
متن شما |
سطر ۱: |
سطر ۱: |
| در این نوع از آسیب پذیری های مهاجم می تواند payload خود را در قسمت های مختلف برنامه تزریق کند. | | در این نوع از آسیب پذیری های مهاجم می تواند payload خود را در قسمت های مختلف برنامه تزریق کند. |
| از انواع آسیب پذیری های injection می توان به تزریق sql و یا تزریق command اشاره کرد. | | از انواع آسیب پذیری های injection می توان به تزریق sql و یا تزریق command اشاره کرد. |
| + | == تزریق sql == |
| زبان پرس و جو sql راهی برای مدیریت داده های ذخیره شده در پایگاه داده های رابطه ای است. | | زبان پرس و جو sql راهی برای مدیریت داده های ذخیره شده در پایگاه داده های رابطه ای است. |
| به این معنا که می توانیم در هر بستری از جمله وب داده هارا ذخیره، ویرایش و یا تغییر دهیم. | | به این معنا که می توانیم در هر بستری از جمله وب داده هارا ذخیره، ویرایش و یا تغییر دهیم. |
سطر ۲۰: |
سطر ۲۱: |
| حملات sql injection نوع های مختلفی دارد. چون به ازای هر query نوشته شده ممکن است حمله جدیدی رخ دهد. | | حملات sql injection نوع های مختلفی دارد. چون به ازای هر query نوشته شده ممکن است حمله جدیدی رخ دهد. |
| با این حال به صورت کلی 3 دسته بندی زیر را می توان نام برد. | | با این حال به صورت کلی 3 دسته بندی زیر را می توان نام برد. |
− | == بر مبنای خطا یا Error Based == | + | === بر مبنای خطا یا Error Based === |
| | | |
| مثال معروفی برای این روش وجود دارد. | | مثال معروفی برای این روش وجود دارد. |
سطر ۷۷: |
سطر ۷۸: |
| </div> | | </div> |
| | | |
− | == بر مبنای تاریکی Blind Based == | + | === بر مبنای تاریکی Blind Based === |
| | | |
| شاید اسم این روش عجیب باشد ولی با توجه به الگو "بر مبنای" تاریکی کلمه مناسب و هکر پسندانه تری است! | | شاید اسم این روش عجیب باشد ولی با توجه به الگو "بر مبنای" تاریکی کلمه مناسب و هکر پسندانه تری است! |
سطر ۱۰۳: |
سطر ۱۰۴: |
| == روش های جلوگیری == | | == روش های جلوگیری == |
| | | |
| + | === کنترل ورودی ها === |
| | | |
− | === روش های جلوگیری در زبان PHP === | + | ==== روش های جلوگیری در زبان PHP ==== |
| | | |
| | | |
سطر ۱۲۱: |
سطر ۱۲۳: |
| </pre> | | </pre> |
| </div> | | </div> |
− |
| |
− | اگر password، مقدار ‘ or ‘a’=’a ‘or’ داشته باشد؛ شرط WHERE به ازای کاربر با کلمه عبور نامرتبط درست خواهد بود.
| |
− |
| |
− | مثال 2)
| |
− |
| |
− | اطلاعات کاربر را با توجه به id او توسط پرس و جو sql دریافت می کنیم.
| |
− |
| |
− | <div lang="en" dir="ltr" class="mw-content-ltr">
| |
− | <pre>
| |
− | $expected_data = 1;
| |
− | $query = "SELECT * FROM users where id=$expected_data"
| |
− | </pre>
| |
− | </div>
| |
− |
| |
− | اگر id، مقدار1; DROP TABLE users; داشته باشد علاوه بر نمایش اطلاعات کاربر جدول کاربران هم پاک می شود!
| |
− | و پرس و جو در نهایت این شکلی می شود.
| |
− |
| |
− | <div lang="en" dir="ltr" class="mw-content-ltr">
| |
− | <pre>
| |
− | SELECT * FROM users where id=1; DROP TABLE users;
| |
− | </pre>
| |
− | </div>
| |
− |
| |
− | برای جلوگیری دو روش Block Malicious و Prepared Statements را بررسی می کنیم.
| |
− |
| |
− | راه حل 1)
| |
− |
| |
− | یکی از بهترین روش ها برای جلوگیری از آسیب پذیری، تشخص کاراکتر های غیر مجاز درون رشته و تبدیل آن ها به کاراکتر های مجاز است.
| |
− |
| |
− | با این توضیح ابتدا تابعی تعریف می کنیم تا ورودی کاربر را بگیرد و کاراکتر های برهم زننده رشته پرس و جو را به کاراکتر های مجاز در رشته در قالب آرایه تبدیل کند.
| |
− |
| |
− | <div lang="en" dir="ltr" class="mw-content-ltr">
| |
− | <pre>
| |
− | <?php
| |
− | function BlockSQLInjection($str)
| |
− | {
| |
− | return str_replace(array("'",""","'",'"'),array("'","""'",""",$str));
| |
− | }
| |
− | ?>
| |
− | </pre>
| |
− | </div>
| |
− |
| |
− | حال درخواست های ارسال شده را به تابع پاس دهیم.
| |
− |
| |
− | <div lang="en" dir="ltr" class="mw-content-ltr">
| |
− | <pre>
| |
− | <?php
| |
− | $userName=BlockSQLInjection($_POST['userName']);
| |
− | $password=BlockSQLInjection($_POST['password']);
| |
− | ?>
| |
− | </pre>
| |
− | </div>
| |
− |
| |
− | راه حل 2)
| |
− |
| |
− | یکی از روش های بسیار خوب استفاده از Prepared Statements ها در زبان های مختلف است.
| |
− |
| |
− | برای مثال در زبان php می توان از PDO برای کار با قسمت های مختلف پایگاه داده در قالب api استفاده کرد.
| |
− |
| |
− | نمونه کد برای کار pdo به شکل زیر است.
| |
− |
| |
− | <div lang="en" dir="ltr" class="mw-content-ltr">
| |
− | <pre>
| |
− | <?php
| |
− | $stmt=$conn->prepare(INSERT INTO MyGuests(firstname,lastname,email)VALUES(?,?,?)");
| |
− | $stmt->bind_param("sss",$firstname,$lastname,$email);
| |
− | //set paramters and execute
| |
− | $firstname="John";
| |
− | $lastname="Doe";
| |
− | | |
− | $stmt->execute();
| |
− | $firstname="Mary";
| |
− | $lastname="Moe";
| |
− | | |
− | $stmt->execute();
| |
− | </pre>
| |
− | </div>
| |
− |
| |
− | === روش های جلوگیری در ASP.NET ===
| |
− |
| |
− | مثال 1)
| |
− | کد زیر را در نظر بگیرید.
| |
− |
| |
− |
| |
− | <div lang="en" dir="ltr" class="mw-content-ltr">
| |
− | <pre>
| |
− | protected void Button1_Click(object sender, EventArgs e)
| |
− | {
| |
− | string connect = "MyConnString"
| |
− | string query = "Select Count(*) From Users Where Username = '" + UserName.Text + "' And Password = '" + Password.Text + "'"
| |
− | int result = 0;
| |
− | using (var conn = new SqlConnection(connect))
| |
− | {
| |
− | using (var cmd = new SqlCommand(query, conn))
| |
− | {
| |
− | conn.Open();
| |
− | result = (int)cmd.ExecuteScalar();
| |
− | }
| |
− | }
| |
− | if (result > 0)
| |
− | {
| |
− | Response.Redirect("LoggedIn.aspx");
| |
− | }
| |
− | else
| |
− | {
| |
− | Literal1.Text = "Invalid credentials"
| |
− | }
| |
− | </pre>
| |
− | </div>
| |
− |
| |
− | همانطور که در رشته پرس و جو مشاهده می کنید، هیچ کنترلی بر روی درخواست ارسال شده نمی شود.
| |
− |
| |
− |
| |
− | اگر مقدار ' or '1' = '1 ارسال شود شرط WHERE درست می شود.
| |
− |
| |
− | مثال 2)
| |
− |
| |
− | در کد زیر هم درخواست ارسال شده بدون هیچ کنترلی در رشته پرس و جو استفاده شده است.
| |
− |
| |
− | <div lang="en" dir="ltr" class="mw-content-ltr">
| |
− | <pre>
| |
− | string connect = "MyConnString"
| |
− | string query = "Select * From Products Where ProductID = " + Request["ID"];
| |
− |
| |
− | using (var conn = new SqlConnection(connect))
| |
− | {
| |
− | using (var cmd = new SqlCommand(query, conn))
| |
− | {
| |
− | conn.Open();
| |
− | //Process results
| |
− | }
| |
− | }
| |
− | </pre>
| |
− | </div>
| |
− |
| |
− | بنابر این اگر مقدار ;Drop Table Admin-- ارسال شود علاوه بر پرس و جوی قبل پرس و جوی ارسال شده اجرا می شود.
| |
− | برای جلوگیری دو روش زیر را بررسی می کنم.
| |
− |
| |
− | راه حل 1)
| |
− |
| |
− | با توجه به نوع ستون جدول در پایگاه داده، ورودی کاربر را تبدیل به آن نوع می کنم.
| |
− |
| |
− | برای مثال id محصول از نوع عدد و int است پس درخواست ارسالی را تبدیل به عدد می کنم.
| |
− |
| |
− | <div lang="en" dir="ltr" class="mw-content-ltr">
| |
− | <pre>
| |
− | protected void Page_Load(object sender, EventArgs e)
| |
− | {
| |
− | var connect = ConfigurationManager.ConnectionStrings["NorthWind"].ToString();
| |
− | var query = "Select * From Products Where ProductID = @ProductID"
| |
− | using (var conn = new SqlConnection(connect))
| |
− | {
| |
− | using (var cmd = new SqlCommand(query, conn))
| |
− | {
| |
− | cmd.Parameters.Add("@ProductID", SqlDbType.Int);
| |
− | cmd.Parameters["@ProductID"].Value = Convert.ToInt32(Request["ProductID"]);
| |
− | conn.Open();
| |
− | //Process results
| |
− | }
| |
− | }
| |
− | }
| |
− | </pre>
| |
− | </div>
| |
− |
| |
− | این روش را می توان به صورت زیر هم استفاده کرد.
| |
− |
| |
− | <div lang="en" dir="ltr" class="mw-content-ltr">
| |
− | <pre>
| |
− | protected void Page_Load(object sender, EventArgs e)
| |
− | {
| |
− | var connect = ConfigurationManager.ConnectionStrings["NorthWind"].ToString();
| |
− | var query = "Select * From Products Where ProductID = @ProductID"
| |
− | using (var conn = new SqlConnection(connect))
| |
− | {
| |
− | using (var cmd = new SqlCommand(query, conn))
| |
− | {
| |
− | cmd.Parameters.AddWithValue("@ProductID", Convert.ToInt32(Request["ProductID"]);
| |
− |
| |
− | conn.Open();
| |
− | //Process results
| |
− | }
| |
− | }
| |
− | }
| |
− | </pre>
| |
− | </div>
| |
− |
| |
− | راه حل 2)
| |
− |
| |
− | روش دیگر استفاده از Store Procedure است.
| |
− |
| |
− | مزیت این روش نسبت به روش قبل این است که query حتما با توجه به نوع ستون اجرا می شود.
| |
− |
| |
− | <div lang="en" dir="ltr" class="mw-content-ltr">
| |
− | <pre>
| |
− | var connect = ConfigurationManager.ConnectionStrings["NorthWind"].ToString();
| |
− | var query = "GetProductByID"
| |
− |
| |
− | using (var conn = new SqlConnection(connect))
| |
− | {
| |
− | using (var cmd = new SqlCommand(query, conn))
| |
− | {
| |
− | cmd.CommandType = CommandType.StoredProcedure;
| |
− | cmd.Parameters.Add("@ProductID", SqlDbType.Int).Value = Convert.ToInt32(Request["ProductID"]);
| |
− | conn.Open();
| |
− | //Process results
| |
− | }
| |
− | }
| |
− | </pre>
| |
− | </div>
| |
− |
| |
− | === روش های جلوگیری در زبان Java ===
| |
− |
| |
− | مثال 1)
| |
− |
| |
− | <div lang="en" dir="ltr" class="mw-content-ltr">
| |
− | <pre>
| |
− | protected void processRequest(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
| |
− | response.setContentType('text/html;charset=UTF-8');
| |
− | PrintWriter out = response.getWriter();
| |
− | try {
| |
− | String user = request.getParameter('user');
| |
− | Connection conn = null;
| |
− | String url = 'jdbc:mysql://192.168.2.128:3306/';
| |
− | String dbName = 'anvayaV2';
| |
− | String driver = 'com.mysql.jdbc.Driver';
| |
− | String userName = 'root';
| |
− | String password = '';
| |
− | try {
| |
− | Class.forName(driver).newInstance();
| |
− | conn = DriverManager.getConnection(url + dbName, userName, password);
| |
− | Statement st = conn.createStatement();
| |
− | String query = 'SELECT * FROM User where userId='' + user + ''';
| |
− | out.println('Query : ' + query);
| |
− | System.out.printf(query);
| |
− | ResultSet res = st.executeQuery(query);
| |
− |
| |
− | out.println('Results');
| |
− | while (res.next()) {
| |
− | String s = res.getString('username');
| |
− | out.println('\t\t' + s);
| |
− | }
| |
− | conn.close();
| |
− | } catch (Exception e) {
| |
− | e.printStackTrace();
| |
− | }
| |
− | } finally {
| |
− | out.close();
| |
− | }
| |
− | </pre>
| |
− | </div>
| |
− |
| |
− | با توجه به کد بالا اگر در userId مقدار admin’ or ‘1’=’1 وارد کنیم رشته پرس و جو به شکل زیر می شود.
| |
− |
| |
− | <div lang="en" dir="ltr" class="mw-content-ltr">
| |
− | <pre>
| |
− | SELECT * FROM User where userId ='admin' or '1'='1'
| |
− | </pre>
| |
− | </div>
| |
− |
| |
− | راه حل 1)
| |
− |
| |
− | با استفاده Prepared Statement نوع درخواست ارسال شده را تعیین می کنیم.
| |
− |
| |
− | <div lang="en" dir="ltr" class="mw-content-ltr">
| |
− | <pre>
| |
− | PreparedStatement preparedStatement=conn.prepareStatement('SELECT * FROM usercheck where username=?') ;
| |
− | preparedStatement.setString(1, user);
| |
− | </pre>
| |
− | </div>
| |
− |
| |
− | راه حل 2)
| |
− |
| |
− | با استفاده از NamedQuery در جاوا می توانیم درخواست را به صورت Prepared Statement دریافت و پرس و جو مرتبط ایجاد کنیم.
| |
− |
| |
− | در حالت عادی query به شکل زیر ساخته می شود.
| |
− |
| |
− | <div lang="en" dir="ltr" class="mw-content-ltr">
| |
− | <pre>
| |
− | String q='SELECT r FROM User r where r.userId=''+user+''';
| |
− | Query query=em.createQuery(q);
| |
− | List users=query.getResultList();
| |
− | </pre>
| |
− | </div>
| |
− |
| |
− | اما با NamedQury می توانیم پرس و جو را با توجه به مدل های پایگاه داده خودکار تولید کنیم.
| |
− |
| |
− | <div lang="en" dir="ltr" class="mw-content-ltr">
| |
− | <pre>
| |
− | Query query=em.createNamedQuery('User.findByUserId');
| |
− | query.setParameter('userId', user);
| |
− | List users=query.getResultList();
| |
− | </pre>
| |
− | </div>
| |
− |
| |
− | === توابع php ===
| |
− |
| |
− | از توابعی که می تواند در بروز این آسیب پذیری موثر باشد می توان به
| |
− |
| |
− | * mysql_query
| |
− | * mysql_db_query
| |
− | * mysql_unbuffered_query
| |
− | * pg_query
| |
− | * pg_send_query
| |
− | * mssql_query
| |
− | * mysqli_query and mysqli::query
| |
− | * mysqli_real_query and mysqli::real_query
| |
− | * mysqli_multi_query and mysqli::multi_query
| |
− | * mysqli_send_query and mysqli::send_query
| |
− | * PDO::query
| |
− | * PDO::exec
| |
− | * PDO::prepar
| |
− |
| |
− | اشاره نمود.
| |
| | | |
| | | |
| [[category:تزریق(Injection)]] | | [[category:تزریق(Injection)]] |