我正在尝试在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);
}
};
答案 0 :(得分:0)
对于与网络相关的请求,您需要将程序集设置为PERMISSION_SET = EXTERNAL_ACCESS
。但是,遗憾的是,使用System.Net.ServicePointManager.ServerCertificateValidationCallback
需要PERMISSION_SET = UNSAFE
。如果您不明确需要覆盖SSL证书的处理,那么您应该删除该委托,因为将Assembly更好地设置为EXTERNAL_ACCESS
。
不幸的是,Visual Studio / SSDT(SQL Server数据工具)使得将程序集设置为EXTERNAL_ACCESS
或UNSAFE
所需的相应步骤变得非常容易。但是,它们可以轻松地将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)(需要免费注册)。
其他说明:
UNSAFE
。所有Convert.ToString(uri)
类型都具有Sql*
属性,该属性返回相应的本机类型。因此请将其替换为.Value
。uri.Value
属性中不需要DataAccess = DataAccessKind.Read
。设置SqlFunction
会略微影响性能,因此,由于您没有使用它,只需将其删除即可。DataAccess = DataAccessKind.Read
和dataStream
(分别是rdr
和Stream
)是"一次性的"对象,所以你真的需要在它们上面调用StreamReader
,而你可以这样做而不是.Dispose()
。.Close()
方法之前发生错误,您的进程可以保持打开外部网络句柄,这可能不会获得释放,直到App Domain回收可能不会持续很长时间。您需要使用Dispose
构造或正确构建using
/ try
/ catch
。在没有执行这两项操作之一的情况下,这是在SQL Server中运行的相当危险的代码。