序言
這個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,使用者名稱,密碼,下載執行病毒木馬程式等等,牛逼的一塌糊塗,好像你的網站系統成啦他自己的一樣。
那麼怎麼注入的呢?舉個例子啊,假如發表個說說,或者微博,發表的內容是 “/>alert(‘123’);中,你再看下你的程式碼成什麼樣子啦,就會執行alert();我這裡僅僅是一個alert();黑客,就黑的不著邊際的黑你啊。
XSS防範:
1、將使用者輸入的特殊符號如:,”,””轉義為<,>,&,”等。
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框架,有的沒有用,有的用的引數化拼接,有的直接字串拼接。那麼我們這麼多專案怎麼一下子進行清理盤查呢。我們想拉個辦法就是我們的專案都有業務邏輯層去連線資料讀寫層的。那麼我們只要把業務邏輯層這一層的方法引數給過濾一下危險字元,不就可以拉。那麼工程開始啦。
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 |
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 { IDictionarystring, object> dic = new Dictionarystring, 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; } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
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業務層事務入侵
讓你的程式碼不用每次都宣告事物,你也不必擔心你的事物是否提交,或者回滾啦嗎?我做了一個示例僅供參考。
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 |
/// /// 插入可以成功 /// public Int32 UpdateTrue(string appName) { try { using (var conn = GetInstance()) { string sql = "update aoptran set appName='"+appName+"' where id "; var result = conn.ExecuteScalar(sql); return result != null ? Convert.ToInt32(result) : 0; } } catch (Exception ex) { return 0; } } /// /// 因為appName欄位多寫成了appName1所以修改不會成功 /// public Int32 UpdateFalse(string appName) { try { using (var conn = GetInstance()) { string sql = "update aoptran set appName1='" + appName + "' where id "; var result = conn.ExecuteScalar(sql); return result != null ? Convert.ToInt32(result) : 0; } } catch (Exception ex) { return 0; } } |
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 |
namespace TranAopRealProxy.Aop { /// /// 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. /// 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(); } /// /// 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. /// /// A System.Runtime.Remoting.Messaging.IMessage that contains a System.Collections.IDictionary // of information about the method call. // /// The message returned by the invoked method, containing the return value and // any out or ref parameters. // 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 /// /// Dependency injection the interception into proxy class. /// /// The interception. public void InterceptionDI(IInterception interception) { _interception = interception; } #endregion } } |
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 |
namespace TranAopRealProxy.Aop { /// /// 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. /// 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(); } /// /// 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. /// /// A System.Runtime.Remoting.Messaging.IMessage that contains a System.Collections.IDictionary // of information about the method call. // /// The message returned by the invoked method, containing the return value and // any out or ref parameters. // 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 /// /// Dependency injection the interception into proxy class. /// /// The interception. public void InterceptionDI(IInterception interception) { _interception = interception; } #endregion } } |
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 |
namespace TranAopRealProxy.Aop { /// /// Description of AOPProxyAttribute. /// [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; } } } |
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 |
using System; namespace TranAopRealProxy.Aop { /// /// Description of IInterception. /// public interface IInterception { /// /// Pre the method invoke. /// void PreInvoke(); /// /// Post the method invoke. /// void PostInvoke(); /// /// Handling the exception which occurs when the method is invoked. /// void ExceptionHandle(); } } |
1 2 3 4 5 6 7 8 9 10 11 |
using System; using System.Collections.Generic; using System.Text; namespace TranAopRealProxy.Aop { interface IProxyDI { void InterceptionDI(IInterception interception); } } |
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 |
// // Authors: // Xiaoliang Pang (mailto:mv@live.cn) // // Copyright (c) 2010 Landpy Software // // http://www.cnblogs.com/pangxiaoliang // using System; using System.Collections.Generic; using System.Text; namespace TranAopRealProxy.Aop { /// /// Null Object pattern for interception. /// public class NullInterception : IInterception { #region IInterception Members /// /// Before invoke the real instance to do something. /// public virtual void PreInvoke() { // Do nothing. } /// /// End invoke the real instance to do something. /// public virtual void PostInvoke() { // Do nothing. } /// /// Handling the exception which occurs when the method is invoked. /// public void ExceptionHandle() { // Do nothing. } #endregion } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
using System; using System.Collections.Generic; using System.Text; namespace TranAopRealProxy.Aop { public class ProxyFactory { public static T CreateProxyInstance(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(); } } } |
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 |
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本質論中的高階方法。同時也歡迎大家加入左上方群,我們一起探討學習。