2016-01-22 43 views
1

我試圖在Visual Studio中調用外部Web服務,但出現錯誤。在Visual Studio中調用外部Web服務時出現安全錯誤

System.Security.SecurityException:請求「System.Security.Permissions.SecurityPermission,mscorlib,Version = 4.0.0.0,Culture = neutral,PublicKeyToken = b77a5c561934e089」類型的權限失敗。 System.Security.SecurityException: 在System.Security.CodeAccessSecurityEngine.Check(對象的需求,StackCrawlMark & stackMark,布爾isPermSet) 在System.Security.CodeAccessPermission.Demand() 在System.Net.ServicePointManager.set_ServerCertificateValidationCallback(RemoteCertificateValidationCallback值)

以下是調用webservice的程序。

public partial class UserDefinedFunctions 
{ 
    [Microsoft.SqlServer.Server.SqlFunction(DataAccess = DataAccessKind.Read)] 
    [return: SqlFacet(MaxSize = -1)] 
    public static SqlString NYP_RestGet(SqlString uri) 
    { 
     String document; 
     System.Net.ServicePointManager.ServerCertificateValidationCallback += 
     delegate(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate, 
           System.Security.Cryptography.X509Certificates.X509Chain chain, 
           System.Net.Security.SslPolicyErrors sslPolicyErrors) 
     { 
      return true; // **** Always accept 
     }; 

     // Set up the request, including authentication 
     WebRequest req = WebRequest.Create(Convert.ToString(uri)); 
     ((HttpWebRequest)req).UserAgent = "CLR web client on SQL Server"; 
     req.ContentType = "application/xml"; 
     ((HttpWebRequest)req).Accept = "application/xml"; 

     WebResponse resp = req.GetResponse(); 
     Stream dataStream = resp.GetResponseStream(); 
     StreamReader rdr = new StreamReader(dataStream); 
     document = (String)rdr.ReadToEnd(); 


     rdr.Close(); 
     dataStream.Close(); 
     resp.Close(); 
     return (document); 
    } 
}; 

回答

0

對於與網絡相關的請求,您需要將您的程序集設置爲PERMISSION_SET = EXTERNAL_ACCESS。但是,不幸的是,使用System.Net.ServicePointManager.ServerCertificateValidationCallback需要PERMISSION_SET = UNSAFE。如果您沒有明確需要覆蓋SSL證書的處理,那麼您應該刪除該代理,因爲將Assembly設置爲EXTERNAL_ACCESS會更好。

不幸的是,Visual Studio/SSDT(SQL Server數據工具)並沒有讓你很容易採取適當的步驟來讓你的程序集被設置爲EXTERNAL_ACCESSUNSAFE。但是,他們確實很容易將TRUSTWORTHY選項設置爲ON,這大多是一個壞主意。

請做不是TRUSTWORTHY ON除非絕對必要!加載沒有構建並且不能重新簽名的程序集時,它只應該是「必要的」。這種情況主要發生在加載「不受支持」且因此尚未存在於SQL Server的CLR主機中的.NET Framework庫時。在這些情況之外,您不應該將數據庫設置爲TRUSTWORTHY ON,因爲它會打開一個安全漏洞。

相反,它是更好的做到以下幾點:

USE [master]; 

CREATE ASYMMETRIC KEY [SomeKey] 
    AUTHORIZATION [dbo] 
    FROM EXECUTABLE FILE = 'C:\path\to\Some.dll'; 

CREATE LOGIN [SomeLogin] 
    FROM ASYMMETRIC KEY [SomeKey]; 

GRANT EXTERNAL ACCESS ASSEMBLY TO [SomeLogin]; -- or "UNSAFE" instead of "EXTERNAL ACCESS" 

以上只需要做的每個實例一次,每個鍵。因此,如果您對所有程序集使用相同的snk/pfx文件,則上述步驟僅需要爲每個SQL Server實例執行一次;包含這些程序集的程序集和數據庫的數量無關緊要。

這種方法可以讓你(通過保持TRUSTWORTHY設置爲OFF),以保持更好的安全性的數據庫,並允許更精細的控制哪些組件,甚至允許設置爲EXTERNAL_ACCESS和/或UNSAFE(因爲你可以通過分離使用不同的密鑰進行簽名和基於這些不同密鑰的登錄)。

有關安全選項的更詳細介紹,請參閱我在SQL Server Central上編寫的以下文章:Stairway to SQLCLR Level 4: Security (EXTERNAL and UNSAFE Assemblies)(需要免費註冊)。


其他說明:

  1. 有關通過SQLCLR調用一般的Web服務和網頁更注意事項,請參閱我的答案在這裏:Call web service from SQL CLR?
  2. 沒有必要使用Convert.ToString(uri)。所有Sql*類型都有一個.Value屬性,該屬性返回適當的本機類型。所以用uri.Value替換它。
  3. 因爲您沒有進行任何數據訪問,所以在SqlFunction屬性中不需要DataAccess = DataAccessKind.Read。設置DataAccess = DataAccessKind.Read是一個輕微的性能打擊,因此,因爲你沒有利用它,只需將其刪除。
  4. dataStreamrdr(分別爲一StreamStreamReader)是「一次性」的對象,所以你真的需要被調用.Dispose()他們,你也許可以做到,而不是.Close()
  5. 您沒有任何錯誤處理,這意味着如果在這兩個對象上調用Dispose方法之前出現錯誤,則您的進程可能會保持打開外部網絡句柄,並且可能不會釋放,直到應用程序域回收可能不會很長時間。您需要使用using構造或正確構造try/catch/finally。這是非常危險的代碼,要在SQL Server中運行而不做這兩件事情之一。
  6. 有關使用SQL Server的CLR主機的各種細微差別的更多詳細信息,請參閱我的文章:Stairway to SQLCLR Level 5: Development (Using .NET within SQL Server)(需要免費註冊)。
相關問題