- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我们正在开发许多 WCF 服务。请求将跨越域边界;也就是说,客户端在一个域中运行,而处理请求的服务器在不同的(生产)域中。我知道如何使用 SSL 和证书保护此链接。我们将询问用户在生产域上的用户名和密码,并在 SOAP header 中传递这些信息。
我的问题是在开发和“beta”测试期间该怎么做。我知道我可以获得一个临时证书并在开发过程中使用它。我想知道我对这种方法的替代方法是什么。在这种情况下,其他人做了什么?
更新:我不确定我的问题是否得到了“好的”答案。我是一个大型开发团队(50 多人)的一员。该组织相当敏捷。任何一位开发人员最终都可能从事使用 WCF 的项目。事实上,其他几个项目也在做类似的事情,但针对不同的网站和服务。我正在寻找一种方式,让我可以让任何人进来并在这个特定项目上工作几天,而不必跳过许多障碍。安装开发证书是其中之一。我完全理解在开发过程中“dogfooding”WCF 结构是最佳实践。大多数答案都给出了答案。我想知道除了“获得一个(或两个)测试证书并将其安装在所有开发人员机器上”之外,还有什么是有意义的。
乔恩
最佳答案
更新: 我们实际上现在使用更简单的 Keith Brown solution 而不是这个,请参阅他提供的源代码。优点:无需维护非托管代码。
如果您仍然想了解如何使用 C/C++ 做到这一点,请继续阅读...
当然只推荐用于开发,而不是生产,但有一种低摩擦的方式来生成 X.509 证书(无需求助于 makecert.exe
)。
如果您可以访问 Windows 上的 CryptoAPI,那么想法是使用 CryptoAPI 调用生成 RSA 公钥和私钥,对新的 X.509 证书进行签名和编码,将其放入仅内存的证书存储区,然后使用 PFXExportCertStore()
生成 .pfx 字节,然后您可以将其传递给 X509Certificate2
构造函数。
一旦你有了一个 X509Certificate2
实例,你就可以将它设置为适当的 WCF 对象的属性,一切就开始工作了。
我有一些我写过的示例代码,当然不能保证任何形式,而且你需要一点 C 经验来编写必须不受管理的位(编写 P/调用所有 CryptoAPI 调用,而不是让那部分在 C/C++ 中)。
使用非托管辅助函数的示例 C# 代码:
public X509Certificate2 GenerateSelfSignedCertificate(string issuerCommonName, string keyPassword)
{
int pfxSize = -1;
IntPtr pfxBufferPtr = IntPtr.Zero;
IntPtr errorMessagePtr = IntPtr.Zero;
try
{
if (!X509GenerateSelfSignedCertificate(KeyContainerName, issuerCommonName, keyPassword, ref pfxSize, ref pfxBufferPtr, ref errorMessagePtr))
{
string errorMessage = null;
if (errorMessagePtr != IntPtr.Zero)
{
errorMessage = Marshal.PtrToStringUni(errorMessagePtr);
}
throw new ApplicationException(string.Format("Failed to generate X.509 server certificate. {0}", errorMessage ?? "Unspecified error."));
}
if (pfxBufferPtr == IntPtr.Zero)
{
throw new ApplicationException("Failed to generate X.509 server certificate. PFX buffer not initialized.");
}
if (pfxSize <= 0)
{
throw new ApplicationException("Failed to generate X.509 server certificate. PFX buffer size invalid.");
}
byte[] pfxBuffer = new byte[pfxSize];
Marshal.Copy(pfxBufferPtr, pfxBuffer, 0, pfxSize);
return new X509Certificate2(pfxBuffer, keyPassword);
}
finally
{
if (pfxBufferPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(pfxBufferPtr);
}
if (errorMessagePtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(errorMessagePtr);
}
}
}
X509GenerateSelfSignedCertificate
函数实现可能是这样的(你需要
WinCrypt.h
):
BOOL X509GenerateSelfSignedCertificate(LPCTSTR keyContainerName, LPCTSTR issuerCommonName, LPCTSTR keyPassword, DWORD *pfxSize, BYTE **pfxBuffer, LPTSTR *errorMessage)
{
// Constants
#define CERT_DN_ATTR_COUNT 1
#define SIZE_SERIALNUMBER 8
#define EXPIRY_YEARS_FROM_NOW 2
#define MAX_COMMON_NAME 8192
#define MAX_PFX_SIZE 65535
// Declarations
HCRYPTPROV hProv = NULL;
BOOL result = FALSE;
// Sanity
if (pfxSize != NULL)
{
*pfxSize = -1;
}
if (pfxBuffer != NULL)
{
*pfxBuffer = NULL;
}
if (errorMessage != NULL)
{
*errorMessage = NULL;
}
if (keyContainerName == NULL || _tcslen(issuerCommonName) <= 0)
{
SetOutputErrorMessage(errorMessage, _T("Key container name must not be NULL or an empty string."));
return FALSE;
}
if (issuerCommonName == NULL || _tcslen(issuerCommonName) <= 0)
{
SetOutputErrorMessage(errorMessage, _T("Issuer common name must not be NULL or an empty string."));
return FALSE;
}
if (keyPassword == NULL || _tcslen(keyPassword) <= 0)
{
SetOutputErrorMessage(errorMessage, _T("Key password must not be NULL or an empty string."));
return FALSE;
}
// Start generating
USES_CONVERSION;
if (CryptAcquireContext(&hProv, keyContainerName, MS_DEF_RSA_SCHANNEL_PROV, PROV_RSA_SCHANNEL, CRYPT_MACHINE_KEYSET) ||
CryptAcquireContext(&hProv, keyContainerName, MS_DEF_RSA_SCHANNEL_PROV, PROV_RSA_SCHANNEL, CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET))
{
HCRYPTKEY hKey = NULL;
// Generate 1024-bit RSA keypair.
if (CryptGenKey(hProv, AT_KEYEXCHANGE, CRYPT_EXPORTABLE | RSA1024BIT_KEY, &hKey))
{
DWORD pkSize = 0;
PCERT_PUBLIC_KEY_INFO pkInfo = NULL;
// Export public key for use by certificate signing.
if (CryptExportPublicKeyInfo(hProv, AT_KEYEXCHANGE, X509_ASN_ENCODING, NULL, &pkSize) &&
(pkInfo = (PCERT_PUBLIC_KEY_INFO)LocalAlloc(0, pkSize)) &&
CryptExportPublicKeyInfo(hProv, AT_KEYEXCHANGE, X509_ASN_ENCODING, pkInfo, &pkSize))
{
CERT_RDN_ATTR certDNAttrs[CERT_DN_ATTR_COUNT];
CERT_RDN certDN[CERT_DN_ATTR_COUNT] = {{1, &certDNAttrs[0]}};
CERT_NAME_INFO certNameInfo = {CERT_DN_ATTR_COUNT, &certDN[0]};
DWORD certNameSize = -1;
BYTE *certNameData = NULL;
certDNAttrs[0].dwValueType = CERT_RDN_UNICODE_STRING;
certDNAttrs[0].pszObjId = szOID_COMMON_NAME;
certDNAttrs[0].Value.cbData = (DWORD)(_tcslen(issuerCommonName) * sizeof(WCHAR));
certDNAttrs[0].Value.pbData = (BYTE*)T2W((LPTSTR)issuerCommonName);
// Encode issuer name into certificate name blob.
if (CryptEncodeObject(X509_ASN_ENCODING, X509_NAME, &certNameInfo, NULL, &certNameSize) &&
(certNameData = (BYTE*)LocalAlloc(0, certNameSize)) &&
CryptEncodeObject(X509_ASN_ENCODING, X509_NAME, &certNameInfo, certNameData, &certNameSize))
{
CERT_NAME_BLOB issuerName;
CERT_INFO certInfo;
SYSTEMTIME systemTime;
FILETIME notBefore;
FILETIME notAfter;
BYTE serialNumber[SIZE_SERIALNUMBER];
DWORD certSize = -1;
BYTE *certData = NULL;
issuerName.cbData = certNameSize;
issuerName.pbData = certNameData;
// Certificate should be valid for a decent window of time.
ZeroMemory(&certInfo, sizeof(certInfo));
GetSystemTime(&systemTime);
systemTime.wYear -= 1;
SystemTimeToFileTime(&systemTime, ¬Before);
systemTime.wYear += EXPIRY_YEARS_FROM_NOW;
SystemTimeToFileTime(&systemTime, ¬After);
// Generate a throwaway serial number.
if (CryptGenRandom(hProv, SIZE_SERIALNUMBER, serialNumber))
{
certInfo.dwVersion = CERT_V3;
certInfo.SerialNumber.cbData = SIZE_SERIALNUMBER;
certInfo.SerialNumber.pbData = serialNumber;
certInfo.SignatureAlgorithm.pszObjId = szOID_RSA_MD5RSA;
certInfo.Issuer = issuerName;
certInfo.NotBefore = notBefore;
certInfo.NotAfter = notAfter;
certInfo.Subject = issuerName;
certInfo.SubjectPublicKeyInfo = *pkInfo;
// Now sign and encode it.
if (CryptSignAndEncodeCertificate(hProv, AT_KEYEXCHANGE, X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED, (LPVOID)&certInfo, &(certInfo.SignatureAlgorithm), NULL, NULL, &certSize) &&
(certData = (BYTE*)LocalAlloc(0, certSize)) &&
CryptSignAndEncodeCertificate(hProv, AT_KEYEXCHANGE, X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED, (LPVOID)&certInfo, &(certInfo.SignatureAlgorithm), NULL, certData, &certSize))
{
HCERTSTORE hCertStore = NULL;
// Open a new temporary store.
if ((hCertStore = CertOpenStore(CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING, NULL, CERT_STORE_CREATE_NEW_FLAG, NULL)))
{
PCCERT_CONTEXT certContext = NULL;
// Add to temporary store so we can use the PFX functions to export a store + private keys in PFX format.
if (CertAddEncodedCertificateToStore(hCertStore, X509_ASN_ENCODING, certData, certSize, CERT_STORE_ADD_NEW, &certContext))
{
CRYPT_KEY_PROV_INFO keyProviderInfo;
// Link keypair to certificate (without this the keypair gets "lost" on export).
ZeroMemory(&keyProviderInfo, sizeof(keyProviderInfo));
keyProviderInfo.pwszContainerName = T2W((LPTSTR)keyContainerName);
keyProviderInfo.pwszProvName = MS_DEF_RSA_SCHANNEL_PROV_W; /* _W used intentionally. struct hardcodes LPWSTR. */
keyProviderInfo.dwProvType = PROV_RSA_SCHANNEL;
keyProviderInfo.dwFlags = CRYPT_MACHINE_KEYSET;
keyProviderInfo.dwKeySpec = AT_KEYEXCHANGE;
// Finally, export to PFX and provide to caller.
if (CertSetCertificateContextProperty(certContext, CERT_KEY_PROV_INFO_PROP_ID, 0, (LPVOID)&keyProviderInfo))
{
CRYPT_DATA_BLOB pfxBlob;
DWORD pfxExportFlags = EXPORT_PRIVATE_KEYS | REPORT_NO_PRIVATE_KEY | REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY;
// Calculate size required.
ZeroMemory(&pfxBlob, sizeof(pfxBlob));
if (PFXExportCertStore(hCertStore, &pfxBlob, T2CW(keyPassword), pfxExportFlags))
{
pfxBlob.pbData = (BYTE *)LocalAlloc(0, pfxBlob.cbData);
if (pfxBlob.pbData != NULL)
{
// Now export.
if (PFXExportCertStore(hCertStore, &pfxBlob, T2CW(keyPassword), pfxExportFlags))
{
if (pfxSize != NULL)
{
*pfxSize = pfxBlob.cbData;
}
if (pfxBuffer != NULL)
{
// Caller must free this.
*pfxBuffer = pfxBlob.pbData;
}
else
{
// Caller did not provide target pointer to receive buffer, free ourselves.
LocalFree(pfxBlob.pbData);
}
result = TRUE;
}
else
{
SetOutputErrorMessage(errorMessage, _T("Failed to export certificate in PFX format (0x%08x)."), GetLastError());
}
}
else
{
SetOutputErrorMessage(errorMessage, _T("Failed to export certificate in PFX format, buffer allocation failure (0x%08x)."), GetLastError());
}
}
else
{
SetOutputErrorMessage(errorMessage, _T("Failed to export certificate in PFX format, failed to calculate buffer size (0x%08x)."), GetLastError());
}
}
else
{
SetOutputErrorMessage(errorMessage, _T("Failed to set certificate key context property (0x%08x)."), GetLastError());
}
}
else
{
SetOutputErrorMessage(errorMessage, _T("Failed to add certificate to temporary certificate store (0x%08x)."), GetLastError());
}
CertCloseStore(hCertStore, 0);
hCertStore = NULL;
}
else
{
SetOutputErrorMessage(errorMessage, _T("Failed to create temporary certificate store (0x%08x)."), GetLastError());
}
}
else
{
SetOutputErrorMessage(errorMessage, _T("Failed to sign/encode certificate or out of memory (0x%08x)."), GetLastError());
}
if (certData != NULL)
{
LocalFree(certData);
certData = NULL;
}
}
else
{
SetOutputErrorMessage(errorMessage, _T("Failed to generate certificate serial number (0x%08x)."), GetLastError());
}
}
else
{
SetOutputErrorMessage(errorMessage, _T("Failed to encode X.509 certificate name into ASN.1 or out of memory (0x%08x)."), GetLastError());
}
if (certNameData != NULL)
{
LocalFree(certNameData);
certNameData = NULL;
}
}
else
{
SetOutputErrorMessage(errorMessage, _T("Failed to export public key blob or out of memory (0x%08x)."), GetLastError());
}
if (pkInfo != NULL)
{
LocalFree(pkInfo);
pkInfo = NULL;
}
CryptDestroyKey(hKey);
hKey = NULL;
}
else
{
SetOutputErrorMessage(errorMessage, _T("Failed to generate public/private keypair for certificate (0x%08x)."), GetLastError());
}
CryptReleaseContext(hProv, 0);
hProv = NULL;
}
else
{
SetOutputErrorMessage(errorMessage, _T("Failed to acquire cryptographic context (0x%08x)."), GetLastError());
}
return result;
}
void
SetOutputErrorMessage(LPTSTR *errorMessage, LPCTSTR formatString, ...)
{
#define MAX_ERROR_MESSAGE 1024
va_list va;
if (errorMessage != NULL)
{
size_t sizeInBytes = (MAX_ERROR_MESSAGE * sizeof(TCHAR)) + 1;
LPTSTR message = (LPTSTR)LocalAlloc(0, sizeInBytes);
va_start(va, formatString);
ZeroMemory(message, sizeInBytes);
if (_vstprintf_s(message, MAX_ERROR_MESSAGE, formatString, va) == -1)
{
ZeroMemory(message, sizeInBytes);
_tcscpy_s(message, MAX_ERROR_MESSAGE, _T("Failed to build error message"));
}
*errorMessage = message;
va_end(va);
}
}
关于wcf - 如何在开发过程中为将在生产过程中受到保护的 WCF 端点避免 SSL 证书,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/582251/
我在 Cloudflare 的域名服务器上有一个域名 example.com。该域指向我的专用服务器的 IP 地址,该服务器运行 CentOS/WHM/cPanel。该站点可访问 - 一切都很好。 我
我正在努力将 SSL 支持添加到我们现有的应用程序中,并已开始考虑向后兼容性。 与我读过的其他帖子不同的一个特殊情况是服务器可能不一定使用 SSL 代码更新。所以我将有一个 SSL 客户端连接到一个对
我有几个 https://*.rest-service.mydomain.com。随着服务数量的增加,我觉得管理 SSL 证书的成本很高。我为 *.mydomain.com 购买了通配符证书。 新添加
我的客户要求我在他的网站上做反向 ssl。但我是这个学期的新手。谁能帮我解决这个问题。 请描述或引用如何做。 最佳答案 查看 this wiki article . In the case of se
关闭。这个问题是opinion-based .它目前不接受答案。 想改进这个问题?更新问题,以便 editing this post 可以用事实和引用来回答它. 去年关闭。 Improve this
我连接到我的网络服务器上的存储库,但是当我尝试推送我的更改时,它显示:“错误 403:需要 ssl”,但在我的存储库设置中我已经激活了 ssl 选项。 有什么建议吗? 最佳答案 当您连接到存储库时,您
抱歉,如果这听起来像是转储问题,我已经阅读了很多关于 SSL 握手和 SSL 工作原理的文章和文档。我对一件事感到困惑,如果有人能澄清我就太好了。 我知道私钥要保密。但是我已经看到通过在请求中指定私钥
随着物联网越来越主流,越来越需要从硬件发送http请求。 一个主要问题是硬件微 Controller 无法发送 ssl 请求,但大多数服务器/网站/服务都在使用 ssl。 所以,问题是,有没有桥(一个
我有一个 ssl 页面,它还从非 ssl 站点下载头像。我能做些什么来隔离该内容,以便浏览器不会警告用户混合内容吗? 最佳答案 只是一个想法 - 或者: 尝试在头像网站上使用 ssl url,如有必要
我在 Digital Ocean droplet(使用 nginx)上设置了两个域。我已经在其中一个(domain1)中安装了一个 SSL 证书,并且那个证书一切正常。第二个域 (domain2) 不
我收到这个错误: Error frontend: 502 Bad gateway 99.110.244:443 2017/09/28 13:03:51 [error] 34080#34080: *10
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 这个问题似乎与 help center 中定义的范围内的编程无关。 . 关闭 6 年前。 Improve
我遇到了一个问题,我正在构建一个 nginx 反向代理以定向到不同 url 路径上的多个微服务。 该系统完全基于 docker,因此开发和生产使用相同的环境。这在安装 SSL 时给我带来了问题,因为
所以我知道要求 SSL 证书和接受之间的根本区别,一个意味着您必须拥有 SSL 证书,另一个意味着您不需要。 在某个网页的 IIS 管理器中,我有以下设置: 我遇到的问题是,当我设置需要 SSL 证书
我今天才发现 .app 域名需要 SSL 证书。我购买它是为了将 DNS 重定向到已经设置了 SSL 证书的站点,所以我的问题是是否可以设置它? 我正在使用 Google Domains,在将合成临时
堆栈 : react ,NGINX 1.14.0,GUnicorn,Django 2.2.8,Python 3.6.9 错误 : 在浏览器:当 React 调用 Django API(当然是在请求头中
假设我在计算机上编辑主机文件以使 google.com 指向我的 VPS 服务器 IP,并且服务器具有通过 Apache 或 Nginx 配置的 google.com 的虚拟主机/服务器 block
我有一个场景,我正在处理用于 URL 路由的 IIS 网站配置。我已添加网站并在服务器上导入所需的证书。 我的情况是(我有多个网站 URL 和两个 SSL 证书 - 如下所示): qatest1.ab
我知道服务器发送的证书无法伪造(仍然存在 MD5 冲突,但成本高昂),但是伪造客户端又如何呢?在中间人攻击中:我们不能告诉服务器我们是合法客户端并从该服务器获取数据并对其进行操作,然后使用合法客户端公
我已通读相关问题,但无法完全找到我要查找的内容。我设置了一个名为“domain.com”的域,并创建了两个子域“client.domain.com”和“client-intern.domain.com
我是一名优秀的程序员,十分优秀!