.Net中的RealProxy實現AOP

来源:http://www.cnblogs.com/knowledgesea/archive/2016/03/31/5308123.html
-Advertisement-
Play Games

序言 這個AOP要從我們公司的一個事故說起,前段時間公司的系統突然在烏雲中出現,數據被泄露的一覽無餘,烏雲上顯示是SQL註入攻擊。呵,多麼貼近生活的一個露洞,可謂是人盡皆知啊。然而卻華麗麗的給拉我們一記耳光。 那麼問題既然來啦,我們.net組有40-50個項目之多吧,怎麼去一一補救這一過失呢?什麼又 ...


序言

這個AOP要從我們公司的一個事故說起,前段時間公司的系統突然在烏雲中出現,數據被泄露的一覽無餘,烏雲上顯示是SQL註入攻擊。呵,多麼貼近生活的一個露洞,可謂是人盡皆知啊。然而卻華麗麗的給拉我們一記耳光。

那麼問題既然來啦,我們.net組有40-50個項目之多吧,怎麼去一一補救這一過失呢?什麼又是SQL註入呢?再有就是常見的Web漏洞有哪些呢?我們怎麼更好的監控我們的系統呢?

那麼大家不要嫌我啰嗦,本篇我將對常見的網站攻擊與防禦,與.Net中AOP實現橫切關註點做一些介紹與演示。

常見的web攻擊與防禦

據數據統計:全球70%的web應用攻擊都是來自XSS攻擊和SQL註入攻擊。此外還有常見的跨站攻擊CSRF,Session劫持,文件上傳等手段。

XSS攻擊

XSS攻擊即跨站點腳本攻擊(Cross Site Script),看下全稱縮寫,本應該是CSS無奈,已被樣式表占用,只能用個更牛逼的XXX代替,XSS,哈哈,蛋扯完啦,說下什麼是XSS,他是攻擊者在網頁中嵌入惡意程式腳本,當用戶打開網頁時,腳本程式便開始執行,竊取客戶端cookie,用戶名,密碼,下載執行病毒木馬程式等等,牛逼的一塌糊塗,好像你的網站系統成啦他自己的一樣。

那麼怎麼註入的呢?舉個例子啊,假如發表個說說,或者微博,發表的內容是  "/><script>alert('123');</script><!-  ,那麼在某種情況下你可能會讓他載入到你的 <input type="text" value="" />中,你再看下你的代碼成什麼樣子啦,就會運行alert();我這裡僅僅是一個alert();黑客,就黑的不著邊際的黑你啊。

XSS防範:

1、將用戶輸入的特殊符號如:<,>,'',""轉義為&lt,&gt,&amp,&quot;等。

2、對Cookie添加HttpOnly屬性,他不能對抗XSS攻擊,但可以防止竊取cookie。

CSRF攻擊

CSRF攻擊即跨站請求攻擊(cross site request forgery)。攻擊者通過跨站請求,以合法用戶的身份進行非法操作,如轉賬,發表評語等。具體流程如下:

舉例說明:假設你在中國銀行網站進行轉賬業務,首先你登陸啦中國銀行,進行啦轉賬,這是假設你的轉賬連接為http:www.zhongguoyinhang/zz/1000.那麼你轉完帳後並沒有關閉頁面。而是訪問啦另外一個網站,另外一個網站的一個圖片或者連接為攻擊者布好的連接:http:www.zhongguoyinhang/zz/1000 。那麼很不幸,你又一次進行啦轉賬。

當然,中國銀行會有各種舉措。不過這確實是攻擊者的一種手段。

CSRF防範:

1、對Cookie添加HttpOnly屬性。

2、增加token驗證,驗證碼驗證,表單token等。

3、通過Referer識別,來源網站。

SQL註入攻擊

SQL註入相信每個開發者都耳熟能詳啦。不多說,就是通過sql拼接,讓你的sql執行別人想要執行的語句。甚至可惡的update,delete,等等等等!!

SQL註入防範:1、使用orm框架。2、使用預編譯語句。3、避免明文存放密碼。4、處理好響應的異常,因為異常中會包含關於伺服器版本,資料庫版本,編程語言甚至資料庫連接地址,用戶名密碼等信息。

文件上傳漏洞

文件上傳也好理解:就是攻擊者上傳啦惡意可執行文件或者腳本,並通過腳本獲取伺服器響應的權利,多可怕,如果他上傳個格式化你伺服器硬碟的程式,可想而知。怕不怕!!

防範:1、驗證尾碼名。2、驗證魔數。魔數:很多類型的文件,其實的幾個位元組內容是固定,因此根據這幾個位元組就能確認文件的類型。這幾個位元組也稱為魔數。3、部署獨立的文件伺服器。

其實攻擊手段還有很多,DDOS,CC,DNS功能變數名稱劫持,cdn回源攻擊等等,大家可以在網上搜搜查查,瞭解一下。

AOP解決40-50個項目中的sql註入漏洞

這裡的aop其實是.Net中的透明代理與真是代理的實現。他讓一般開發者不用關心某個橫切點,比如介面性能的的記錄,日誌記錄,過濾危險字元,事物提交回滾等等。

首先我們的項目有的用的orm框架,有的沒有用,有的用的參數化拼接,有的直接字元串拼接。那麼我們這麼多項目怎麼一下子進行清理盤查呢。我們想拉個辦法就是我們的項目都有業務邏輯層去連接數據讀寫層的。那麼我們只要把業務邏輯層這一層的方法參數給過濾一下危險字元,不就可以拉。那麼工程開始啦。

namespace A.Helper.Client.Action
{
    public class SqlVerifyProxy :RealProxy
    {
        MarshalByRefObject _target = null;
        public SqlVerifyProxy(Type type, MarshalByRefObject target)
            : base(type)
        {
            this._target = target;
        }
        //覆寫Invoke,處理RealProxy截獲的各種消息,
        //此種方式最簡捷,但不能截獲遠程對象的激活,好在我們並不是真的要Remoting
        public override IMessage Invoke(IMessage msg)
        {
            IMethodCallMessage call = (IMethodCallMessage)msg;
            IConstructionCallMessage ctr = call as IConstructionCallMessage;
            IMethodReturnMessage back = null;
            //構造函數,只有ContextBoundObject(Inherit from MarshalByRefObject)對象才能截獲構造函數
            if (ctr != null)
            {
                RealProxy defaultProxy = RemotingServices.GetRealProxy(_target);
                //如果不做下麵這一步,_target還是一個沒有直正實例化被代理對象的透明代理,
                //這樣的話,會導致沒有直正構建對象。
                defaultProxy.InitializeServerObject(ctr);
                //本類是一個RealProxy,它可通過GetTransparentProxy函數得到透明代理
                back = EnterpriseServicesHelper.CreateConstructionReturnMessage(ctr, (MarshalByRefObject)GetTransparentProxy());
            }
            //MarshalByRefObject對象就可截獲普通的調用消息,
            //MarshalByRefObject對象告訴編譯器,不能將其內部簡單的成員函數優化成內聯代碼,
            //這樣才能保證函數調用都能截獲。
            else
            {
                IDictionary<string, object> dic = new Dictionary<string, object>();
                dic = actionContext.ActionArguments;
                if (dic != null && dic.Count > 0)
                {
                    foreach (var m in dic)
                    {
                        string o = m.Value.ToJson();
                        Utils.Filter(o);
                    }
                }
                back = RemotingServices.ExecuteMessage(_target, call);                
            }
            return back;
        }
    }
}
namespace A.Helper.Client.Action
{
    //從ProxyAttribute繼承,自動實現RealProxy植入
    [AttributeUsage(AttributeTargets.Class)]
    class SqlVerifyProxyAttribute : ProxyAttribute
    {
        //覆寫CreateInstance函數,返回我們自建的代理
        public override MarshalByRefObject CreateInstance(Type serverType)
        {
            MarshalByRefObject obj = base.CreateInstance(serverType);
            SqlVerifyProxy proxy = new SqlVerifyProxy(serverType, obj);
            return (MarshalByRefObject)proxy.GetTransparentProxy();
        }
    }
}

好啦,就這麼簡單,只要業務邏輯層的基類,集成ContextBoundObject添加我們的[SqlVerifyProxy]屬性就好啦,這個作為一個dll給其他項目引入,別人不用一個一個再寫一遍。不過這也是我們的權宜之計,相信我們以後的項目會有更好的架構設計,來防範諸如此類低級問題的發生。

RealProxy實現AOP業務層事務入侵

讓你的代碼不用每次都聲明事物,你也不必擔心你的事物是否提交,或者回滾啦嗎?我做了一個示例僅供參考。

        /// <summary>
        /// 插入可以成功
        /// </summary>  
        public Int32 UpdateTrue(string appName)
        {
            try
            {
                using (var conn = GetInstance())
                {
                    string sql = "update aoptran set appName='"+appName+"' where id <10 ";
                    var result = conn.ExecuteScalar(sql);
                    return result != null ? Convert.ToInt32(result) : 0;
                }
            }
            catch (Exception ex)
            {               
                return 0;
            }
        }
        /// <summary>
        /// 因為appName欄位多寫成了appName1所以修改不會成功
        /// </summary>  
        public Int32 UpdateFalse(string appName)
        {
            try
            {
                using (var conn = GetInstance())
                {
                    string sql = "update aoptran set appName1='" + appName + "' where id <10 ";
                    var result = conn.ExecuteScalar(sql);
                    return result != null ? Convert.ToInt32(result) : 0;
                }
            }
            catch (Exception ex)
            {
                return 0;
            }
        }
namespace TranAopRealProxy.Aop
{
    /// <summary>
    /// RealProxy is a abstract class, which is a class in Framework to provide the function about base proxy.
    /// The Invoke method like the hook of MFC, it intercept the message, inject the custom logic and generate a new message
    /// for system to performance.
    /// </summary>
    class AOPRealProxy : RealProxy, IProxyDI
    {
        private MarshalByRefObject _target = null;
        private IInterception _interception = null;

        public AOPRealProxy(Type targetType, MarshalByRefObject target)
            : base(targetType)
        {
            _target = target;
            _interception = new NullInterception();
        }

        /// <summary>
        /// Overridden the method "Invoke" of the base class, invokes the method that is specified
        //  in the provided System.Runtime.Remoting.Messaging.IMessage on the remote
        //  object that is represented by the current instance.
        /// </summary>
        /// <param name="msg">A System.Runtime.Remoting.Messaging.IMessage that contains a System.Collections.IDictionary
        //  of information about the method call.
        //  </param>
        /// <returns>The message returned by the invoked method, containing the return value and
        //  any out or ref parameters.
        //  </returns>
        public override System.Runtime.Remoting.Messaging.IMessage Invoke(System.Runtime.Remoting.Messaging.IMessage msg)
        {
            IMethodReturnMessage methodReturnMessage = null;
            IMethodCallMessage methodCallMessage = msg as IMethodCallMessage;//Check whether the message is method call message.
            if (methodCallMessage != null)
            {
                IConstructionCallMessage constructionCallMessage = methodCallMessage as IConstructionCallMessage;
                if (constructionCallMessage != null)
                {
                    RealProxy defaultProxy = RemotingServices.GetRealProxy(_target);
                    defaultProxy.InitializeServerObject(constructionCallMessage);
                    methodReturnMessage = EnterpriseServicesHelper.CreateConstructionReturnMessage(constructionCallMessage, (MarshalByRefObject)GetTransparentProxy());
                }
                else
                {
                    _interception.PreInvoke();
                    try
                    {
                        methodReturnMessage = RemotingServices.ExecuteMessage(_target, methodCallMessage);
                    }
                    catch
                    {
                    }
                    if (methodReturnMessage.Exception != null)
                    {
                        _interception.ExceptionHandle();
                    }
                    else
                    {
                        _interception.PostInvoke();
                    }
                }
            }
            return methodReturnMessage;
        }

        #region IProxyDI Members

        /// <summary>
        /// Dependency injection the interception into proxy class.
        /// </summary>
        /// <param name="interception">The interception.</param>
        public void InterceptionDI(IInterception interception)
        {
            _interception = interception;
        }

        #endregion
    }
}
View Code
namespace TranAopRealProxy.Aop
{
    /// <summary>
    /// Description of AOPProxyAttribute.
    /// </summary>
    [AttributeUsage(AttributeTargets.Class)]
    public class AOPProxyAttribute : ProxyAttribute
    {
        private IInterception _interception;
        public Type Interception
        {
            get 
            {
                return _interception.GetType();
            }
            set
            {
                IInterception interception = Activator.CreateInstance(value) as IInterception;
                _interception = interception;
            }
        }
        public AOPProxyAttribute()
        {
            _interception = new NullInterception();
        }
        public override MarshalByRefObject CreateInstance(Type serverType)
        {
            MarshalByRefObject target = base.CreateInstance(serverType);
            AOPRealProxy aopRealProxy = new AOPRealProxy(serverType, target);
            aopRealProxy.InterceptionDI(_interception);
            return aopRealProxy.GetTransparentProxy() as MarshalByRefObject;
        }
    }
}
View Code
using System;

namespace TranAopRealProxy.Aop
{
    /// <summary>
    /// Description of IInterception.
    /// </summary>
    public interface IInterception
    {
        /// <summary>
        /// Pre the method invoke.
        /// </summary>
        void PreInvoke();

        /// <summary>
        /// Post the method invoke.
        /// </summary>
        void PostInvoke();

        /// <summary>
        /// Handling the exception which occurs when the method is invoked.
        /// </summary>
        void ExceptionHandle();
    }
}
View Code
using System;
using System.Collections.Generic;
using System.Text;

namespace TranAopRealProxy.Aop
{
    interface IProxyDI
    {
        void InterceptionDI(IInterception interception);
    }
}
View Code
//
// Authors:
// Xiaoliang Pang (mailto:[email protected])
//
// Copyright (c) 2010 Landpy Software
//
// http://www.cnblogs.com/pangxiaoliang
//
using System;
using System.Collections.Generic;
using System.Text;

namespace TranAopRealProxy.Aop
{
    /// <summary>
    /// Null Object pattern for interception.
    /// </summary>
    public class NullInterception : IInterception
    {

        #region IInterception Members

        /// <summary>
        /// Before invoke the real instance to do something.
        /// </summary>
        public virtual void PreInvoke()
        {
            // Do nothing.
        }

        /// <summary>
        /// End invoke the real instance to do something.
        /// </summary>
        public virtual void PostInvoke()
        {
            // Do nothing.
        }

        /// <summary>
        /// Handling the exception which occurs when the method is invoked.
        /// </summary>
        public void ExceptionHandle()
        {
            // Do nothing.
        }

        #endregion

    }
}
View Code
using System;
using System.Collections.Generic;
using System.Text;

namespace TranAopRealProxy.Aop
{
    public class ProxyFactory
    {
        public static T CreateProxyInstance<T>(IInterception interception) where T : new()
        {
            Type serverType = typeof(T);
            MarshalByRefObject target = Activator.CreateInstance(serverType) as MarshalByRefObject;
            AOPRealProxy aopRealProxy = new AOPRealProxy(serverType, target);
            aopRealProxy.InterceptionDI(interception);
            return (T)aopRealProxy.GetTransparentProxy();
        }
    }
}
View Code
using System.Text;
using System.Threading.Tasks;
using TranAopRealProxy.Aop;
using System.Transactions;
namespace TranAopRealProxy.Aop
{
    /// <summary>
    /// The interception of the AOP for trasaction.
    /// </summary>
    class Transaction : IInterception
    {
        #region IInterception Members

        TransactionScope tran = null;
        public void ExceptionHandle()
        {
            tran.Dispose();
        }
        public void PostInvoke()
        {
            tran.Complete();
            tran.Dispose();
        }
        public void PreInvoke()
        {
            tran = new TransactionScope();             
        }
        #endregion
    }
}
 public class Logic : BaseTran
    {
        /// <summary>
        /// 回滾
        /// </summary>
        public void ActionFalseRollBack()
        {
            DoDB db = new DoDB();
            db.UpdateTrue("abc");
            int isSuccess= db.UpdateFalse("defg");
            if (isSuccess <=0)
            {
                throw new Exception("蒼天啊,大地啊,回滾吧。");
            }
        }
        /// <summary>
        /// 提交
        /// </summary>
        public void ActionFalseRollBack1()
        {
            DoDB db = new DoDB();
            db.UpdateTrue("abc");
            db.UpdateTrue("abc234");           
        }
    }

總結

AOP在.net中還有體現,比如mvc的過濾器。也有很多第三方的插件供我們使用,比如:postsharp,castle.net等,大家可以瞭解學習下。如果你想把這裡的透明代理與真實代理學透徹,也推薦閱讀.Net本質論中的高級方法。同時也歡迎大家加入左上方群,我們一起探討學習。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • <!--?xml version="1.0" encoding="UTF-8" standalone="no"?--> 當你在swift中編寫一個類時,預設其中任何屬性,方法都能被外部訪問的。有的時候我們不希望屬性或方法被外部訪問,希望私有化。 在swift中有三個關鍵字 public : 公共訪問 ...
  • 重定向和轉發有一個重要的不同:當使用轉發時,JSP容器將使用一個內部的方法來調用目標頁面,新的頁面繼續處理同一個請求,而瀏覽器將不會知道這個過程。 與之相反,重定向方式的含義是第一個頁面通知瀏覽器發送一個新的頁面請求。因為,當你使用重定向時,瀏覽器中所顯示的URL會變成新頁面的URL, 而當使用轉發 ...
  • java中equal和==的區別: equal方法除非進行了重寫(比如String類和基本類型包裝類),否則都是進行對象引用的比較。而==除了比較基本類型時是比較值,其他情況均是比較引用地址。 java適配器模式? 將原來的實現介面所有方法變成了繼承實現了介面方法的抽象類(adapter),然後再實 ...
  • 公司應用項目在客戶部署時經常遇到此類問題,為避免實施部署時增加配置量,花了點時間找到了此問題的終極解決辦法(方案二、修改org.hibernate.hql.ast.HqlLexer的源代碼)。在此進行記錄本問題的分析解決方案。 一、問題現象描述: 1、異常信息: 'weblogic.kernel.D ...
  • 原文轉自:http://www.zccode.com/thread-724-1-1.html 該資源說明:看起來不錯的一套一元雲購CMS源碼,源碼包裡面帶了安卓和ios手機客戶端,手機客戶端需要自己反編譯。 這裡不做功能和其它更多的介紹,可以自己下載後慢慢測試瞭解。安裝說明:伺服器空間需要支持PHP ...
  • 問題的提出整個WR的ISE工程比較大,編譯時間很長,導致開發效率低。通過分析發現,ISE在綜合的時候大量的時間都花在了初始化DPRAM上。調研發現Xilinx提供了BMM文件和DATA2MEM工具,可以將軟核CPU的運行代碼在HDL綜合完後再與bit文件合併,這樣可以節約大量的編譯時間。但是在wr工 ...
  • Atitit.android jsbridge v1新特性 1. Java代碼調用js並傳參其實是通過WebView的loadUrl方法去調用的、只是參數url的寫法不一樣而已1 2. 三、JAVA和JS交互註意事項1 3. Js調用android java通過jsbridge2 4. JsBrid ...
  • 介紹 智能企業(intelligent enterprise)就是全面運用智能管理體系,實現企業管理中“機要素智能化高效整合併實現人機協調”的企業。信息管理中經常談到“人機協調”的問題.這裡所說的“人機協調含義有所不同。信息管理中的人機協調更多的是研究技術上的問題,這裡的人機協調強調的是管理問題,必... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...