上一篇文章地址:
構建安全的Xml Web Service系列一之初探使用Soap頭 (5-22 12:53)????
???? 要分析Xml Web Service的安全性,首先要解決的問題是我們能了解和清楚Soap消息的格式和內容,如果獲得不了SoapMessage,分析如何能構建安全Xml web service也就無從下手,即使分析出來,自己也可 能模模糊糊,不能定論。下面就分析下如何獲得SoapMessage。
??? 首先介紹一個類-SoapExtension,msdn對這個類的備注為:ASP.NET 允許通過擴展性機制生成與 SOAP 相關的基礎結構。ASP.NET SOAP 擴展結構以一種擴展為中心,
該擴展可以在客戶端或服務器上處理消息時在特定階段中檢查或修改消息。ASP.NET SOAP 擴展從 SoapExtension 類派生。GetInitializer 和 Initialize 方法提供其他可用機制,用于初始化 SOAP 擴展以增強性能。
ProcessMessage 是大多數 SOAP 擴展的核心,原因是該方法在 SoapMessageStage 中定義的每一個階段都被調用,從而使 SOAP 擴展得以執行所需的該特定 SOAP 擴展的行為。對于需要修改 SOAP 請求或 SOAP 響應的 SOAP 擴展,ChainStream 提供一個機會以接收要通過網絡發送的建議數據。 仔細閱讀這段文字,如果您以前開發過windows程序,那第一個應該想到的是:原來web service的處理機制和windows窗口程序的消息機制竟然有著一曲同工之妙。下面談談如何利用這個類,來截獲Xml web Service請求和相應的Soap消息,從而看看xml web service的廬山真面目。
??? 首先大家先看看這個類,這個類完成的功能是將Xml Web Service通過擴展的方式,將每次的請求和響應的Soap消息通過日志的方式保存到文本文件中。日志記錄的方式也有兩種:
??? 1。針對每個WebMethod產生一個日志文件。
????2。針對每個WebService產生一個日志文件
?因為一個WebService可能包含一個或者多個WebMethod,所以如果指定兩種方法都支持的話,那第二個日志兩面應該包括第一個日志里面的內容,而有些情況下,是不需要對每個WebMethod都進行日志記錄的,這時候采用第一種記錄方式,增強了系統的靈活性。?
下面是擴展了的SoapExtension
?<webServices>
????????<soapExtensionTypes>
??????????<add?type="Jillzhang.TraceExtension,Jillzhang"?priority="1"??group="High"??/>
????????</soapExtensionTypes>
??????</webServices> 
可以記錄SoapMessage的SoapExtension
namespace?Jillzhang
{
????public?class?TraceExtension:?SoapExtension
????{
????????static?readonly?string?LogRoot?=?System.Configuration.ConfigurationManager.AppSettings["logRoot"];
????????Stream?oldStream;
????????Stream?newStream;
????????string?filename;

???????///?<summary>
???????///?將請求流和響應流存到內存流中,已被調用
???????///?</summary>
????????///?<param?name="stream">包含?SOAP?請求或響應的內存緩沖區</param>
????????///?<returns>它表示此?SOAP?擴展可以修改的新內存緩沖區。</returns>
????????public?override?Stream?ChainStream(Stream?stream)
????????{
????????????oldStream?=?stream;
????????????newStream?=?new?MemoryStream();
????????????return?newStream;
????????}

????????///?<summary>
????????///?在Xml?Web?Service第一次運行的時候,一次性的將通過TraceExtensionAttribute傳遞進來的
????????///?保存日志信息的文件名初始化
????????///?</summary>
????????///?<param?name="methodInfo">應用?SOAP?擴展的?XML?Web?services?方法的特定函數原型</param>
????????///?<param?name="attribute">應用于?XML?Web?services?方法的?SoapExtensionAttribute</param>
????????///?<returns>SOAP?擴展將對其進行初始化以用于緩存</returns>
????????public?override?object?GetInitializer(LogicalMethodInfo?methodInfo,?SoapExtensionAttribute?attribute)
????????{
????????????return?((TraceExtensionAttribute)attribute).Filename;
????????}

????????///?<summary>
????????///?替代為每個方法配置的保存SoapMessage文件名,而是將整個網絡服務
????????///?的SoapMessage都保存到一個日志文件中,這個文件路徑需要在Web?Service
????????///?的配置文件中web.config指出,如
????????///?<appSettings>
????????///??<add?key="logRoot"?value="c:\\serviceLog"/>
????????///?</appSettings>
????????///?</summary>
????????///?<param?name="WebServiceType">網絡服務的類型</param>
????????///?<returns>用于保存日志記錄的文件路徑</returns>
????????public?override?object?GetInitializer(Type?WebServiceType)
????????{
????????????//return?LogRoot.TrimEnd('\\')?+?"\\"?+?WebServiceType.FullName?+?".log";
????????????return?LogRoot.TrimEnd('\\')+"\\"+?WebServiceType.FullName?+?".log";
????????}

????????//獲得文件名,并將其保存下來
????????public?override?void?Initialize(object?initializer)
????????{
????????????filename?=?(string)initializer;
????????}

???????///?<summary>
???????///?當數據還為Soap格式的時候,將數據寫入日志
???????///?</summary>
???????///?<param?name="message"></param>
????????public?override?void?ProcessMessage(SoapMessage?message)
????????{
????????????switch?(message.Stage)
????????????{
????????????????case?SoapMessageStage.BeforeSerialize:
????????????????????break;
????????????????case?SoapMessageStage.AfterSerialize:
????????????????????WriteOutput(message);
????????????????????break;
????????????????case?SoapMessageStage.BeforeDeserialize:
????????????????????WriteInput(message);
????????????????????break;
????????????????case?SoapMessageStage.AfterDeserialize:
????????????????????break;
????????????????default:
????????????????????throw?new?Exception("invalid?stage");
????????????}
????????}
????????///?<summary>
????????///?將SoapMessage寫入到日志文件
????????///?</summary>
????????///?<param?name="message"></param>
????????public?void?WriteOutput(SoapMessage?message)
????????{
????????????newStream.Position?=?0;?
????????????//創建或追加記錄文件
????????????FileStream?fs?=?new?FileStream(filename,?FileMode.Append,
????????????????FileAccess.Write);
????????????StreamWriter?w?=?new?StreamWriter(fs);
????????????string?soapString?=?(message?is?SoapServerMessage)???"Soap響應"?:?"Soap請求";
????????????w.WriteLine("-----"?+?soapString?+?"?在?"?+?DateTime.Now.ToString("yyyy年MM月dd日?HH時mm分ss秒"));
????????????w.Flush();
????????????Copy(newStream,?fs);
????????????w.Close();
????????????newStream.Position?=?0;
????????????Copy(newStream,?oldStream);
????????}

????????public?void?WriteInput(SoapMessage?message)
????????{
????????????Copy(oldStream,?newStream);
????????????FileStream?fs?=?new?FileStream(filename,?FileMode.Append,
????????????????FileAccess.Write);
????????????StreamWriter?w?=?new?StreamWriter(fs);

????????????string?soapString?=?(message?is?SoapServerMessage)??
?????????????????"Soap請求"?:?"Soap響應";
????????????w.WriteLine("-----"?+?soapString?+
????????????????"?在?"?+?DateTime.Now.ToString("yyyy年MM月dd日?HH時mm分ss秒"));
????????????w.Flush();
????????????newStream.Position?=?0;
????????????Copy(newStream,?fs);
????????????w.Close();
????????????newStream.Position?=?0;
????????}
????????///?<summary>
????????///?拷貝流到流
????????///?</summary>
????????///?<param?name="from"></param>
????????///?<param?name="to"></param>
????????void?Copy(Stream?from,?Stream?to)
????????{
????????????TextReader?reader?=?new?StreamReader(from);
????????????TextWriter?writer?=?new?StreamWriter(to);
????????????writer.WriteLine(reader.ReadToEnd());
????????????writer.Flush();
????????}
????}

????//創建一個用于在WebMethod上使用的SoapExtension屬性
????[AttributeUsage(AttributeTargets.Method)]
????public?class?TraceExtensionAttribute?:?SoapExtensionAttribute
????{

????????private?string?filename?=?"c:\\log.txt";
????????private?int?priority;

????????///?<summary>
????????///?擴展類型
????????///?</summary>
????????public?override?Type?ExtensionType
????????{
????????????get?{?return?typeof(TraceExtension);?}
????????}
????????///?<summary>
????????///?優先級?
????????///?</summary>
????????public?override?int?Priority
????????{
????????????get?{?return?priority;?}
????????????set?{?priority?=?value;?}
????????}
????????///?<summary>
????????///?用于記錄該WebMethod的SoapMessage的文件的絕對路徑
????????///?默認為c:\\log.txt;
????????///?</summary>
????????public?string?Filename
????????{
????????????get
????????????{
????????????????return?filename;
????????????}
????????????set
????????????{
????????????????filename?=?value;
????????????}
????????}
????}???
}

結下來,介紹一個如何使用該類:
如果要使讓TraceExtension支持第一種記錄方式,需要作的額外工作為:
只需要在要記錄SoapMessage的WebMethod添加如下的Attribute
[TraceExtension(Filename="d:\\data.xml",Priority=0)]
當然路徑,您可以自己設定
前一節的WebMethod就變成了

添加了針對WebMethod日志記錄的WebMethod
?public?MySoapHeader?header?=?new?MySoapHeader();????????
????????[WebMethod]
????????[SoapHeader("header")]???
????????[TraceExtension(Filename="d:\\data.xml",Priority=0)]
????????public?string?HelloWorld()
????????{
????????????if?(header?==?null)
????????????{
????????????????return?"您沒有設置SoapHeader,不能正常訪問此服務!";
????????????}
????????????if?(header.UserName?!=?"jillzhang"?||?header.Pwd?!=?"123456")
????????????{
????????????????return?"您提供的身份驗證信息有誤,不能正常訪問此服務!";
????????????}
????????????return?"Hello?World";
????????} 調用下該WebService,便在d盤產生一個data.xml文件,里面的內容為:

日志記錄
-----Soap請求?在?2007年05月25日?09時06分29秒
<?xml?version="1.0"?encoding="utf-8"?><soap:Envelope?xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"?xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"?xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Header><MySoapHeader?xmlns="http://tempuri.org/"><UserName>jillzhang</UserName><Pwd>123456</Pwd></MySoapHeader></soap:Header><soap:Body><HelloWorld?xmlns="http://tempuri.org/"?/></soap:Body></soap:Envelope>


-----Soap響應?在?2007年05月25日?09時06分29秒
<?xml?version="1.0"?encoding="utf-8"?><soap:Envelope?xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"?xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"?xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><HelloWorldResponse?xmlns="http://tempuri.org/"><HelloWorldResult>Hello?World</HelloWorldResult></HelloWorldResponse></soap:Body></soap:Envelope>

如何采用第二種方法,讓WebService的每個WebMethod都能記錄日志
需要在Web.config中作如下的設定
首先添加如下節點
?<webServices>
????????<soapExtensionTypes>
??????????<add?type="Jillzhang.TraceExtension,Jillzhang"?priority="1"??group="High"??/>
????????</soapExtensionTypes>
??????</webServices> 然后通過配置設定日志文件保留的路徑:
<appSettings>
????<add?key="logRoot"?value="d:"/>
??</appSettings> 找到日志文件,里面也赫然有著SoapMessage的真面目。通過以上方法,大家可以清晰地分析到SoapMessage的具體格式和內容,知道了這個以后,對付Web Service,您就可以隨心應手,隨心所欲,如果你愿意,你甚至也可以“強奸"一次webservice,哈哈!
上一篇文章地址:
構建安全的Xml Web Service系列一之初探使用Soap頭 (5-22 12:53)
附:終于買上房了,雖然買的過程很累,但現在還是很Happy!