在visual studio中调用外部Web服务时出现安全性错误

时间:2016-01-22 17:17:32

标签: web-services visual-studio-2012 sqlclr

我正在尝试在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,Boolean isPermSet)        在System.Security.CodeAccessPermission.Demand()        在System.Net.ServicePointManager.set_ServerCertificateValidationCallback(RemoteCertificateValidationCallback value)

以下是调用Web服务的程序。

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);
    }
};

1 个答案:

答案 0 :(得分: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!它应该只是必要的"加载您未构建且无法重新签名的程序集时。这主要发生在加载不受支持的.NET Framework库时#34;因此还没有在SQL Server的CLR主机中。在这些情况之外,您不应该将数据库设置为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),并允许更精细地控制甚至允许将哪些程序集设置为{{1} }和/或EXTERNAL_ACCESS(因为您可以使用不同的键进行分离,并根据这些不同的键进行登录)。

有关安全选项的更详细介绍,请参阅我在SQL Server Central上编写的以下文章:Stairway to SQLCLR Level 4: Security (EXTERNAL and UNSAFE Assemblies)(需要免费注册)。

其他说明:

  1. 有关通过SQLCLR调用Web服务和网页的更多说明,请在此处查看我的答案:Call web service from SQL CLR?
  2. 无需使用UNSAFE。所有Convert.ToString(uri)类型都具有Sql*属性,该属性返回相应的本机类型。因此请将其替换为.Value
  3. 由于您没有进行任何数据访问,因此uri.Value属性中不需要DataAccess = DataAccessKind.Read。设置SqlFunction会略微影响性能,因此,由于您没有使用它,只需将其删除即可。
  4. DataAccess = DataAccessKind.ReaddataStream(分别是rdrStream)是"一次性的"对象,所以你真的需要在它们上面调用StreamReader,而你可以这样做而不是.Dispose()
  5. 您没有任何错误处理,这意味着如果在这两个对象上调用.Close()方法之前发生错误,您的进程可以保持打开外部网络句柄,这可能不会获得释放,直到App Domain回收可能不会持续很长时间。您需要使用Dispose构造或正确构建using / try / catch。在没有执行这两项操作之一的情况下,这是在SQL Server中运行的相当危险的代码。
  6. 有关使用SQL Server的CLR主机的各种细微差别的详细信息,请参阅我的文章:Stairway to SQLCLR Level 5: Development (Using .NET within SQL Server)(需要免费注册)。