今天系统上线一个需要对一个原有老系统做一些安全防范,发现很多老旧的传统Soap Web Servcie对公网开放访问,自然想到用白名单对调用方加以限制。这里自然想到采用nginx做为反向代理服务器转发请求到iis上,于是便有了如下配置。
server {
listen 8080;
location / {
proxy_pass http://127.0.0.1:8090;
client_max_body_size 1024m;
proxy_connect_timeout 3000;
proxy_next_upstream_timeout 3000;
proxy_read_timeout 3000;
proxy_send_timeout 3000;
}
if ($time_iso8601 ~ "^(\d{4})-(\d{2})-(\d{2})T(\d{2})")
{
set $year $1;
set $month $2;
set $day $3;
}
access_log logs/$year-$month-$day-8080.xxx.com-access.log main;
}
这里对原先在8090 端口上运行的服务转给8080,对外网可以访问这样以后可以增加白名单等操作。
完成修改后 访问 http://external-ip:8080/test.asmx 顺利看到了测试界面于是感觉已经完成了配置,但是同事测试了一个接口地址,发现了特别神奇的问题如访问:
http://external-ip:8080/test.asmx?op=GetCBInfo 输入测试参数则在浏览器中发现请求被转发到了
http://127.0.0.1:8090/test.asmx?op=GetCBInfo 自然是请求不能访问的。
观察了下测试界面发现了不用于原来通过IIS直接访问,Soap web 服务的Host头似乎发生了变化,变成了127.0.0。1猜测是.net soap servie是根据访问的host头进行的host的设置的,而IIS直接访问就是外网ip或者域名,而进过nginx转发,则实践访问的host确实没有了外网ip了。于是修改为如下配置。
server {
listen 8080;
location / {
proxy_pass http://webservie;
client_max_body_size 1024m;
proxy_connect_timeout 3000;
proxy_next_upstream_timeout 3000;
proxy_read_timeout 3000;
proxy_send_timeout 3000;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
}
if ($time_iso8601 ~ "^(\d{4})-(\d{2})-(\d{2})T(\d{2})")
{
set $year $1;
set $month $2;
set $day $3;
}
access_log logs/$year-$month-$day-8080.xxx.com-access.log main;
}
重新加载nginx配置后,发现请求转发的地址确实对了,但是端口不对,为8089内网的端口,于是只有查找更多的文档,发现了如下两行配置
sub_filter http://external-ip:8090/ http://expternal-ip:8080/;
sub_filter '<soap:address location="http://extenal-ip:8090/' '<soap:address location="http://extenal-ip:8080/';
sub_filter_once off;
加入到location内,发现生效了转发有效,接口调用正常。
原理探究:
首先什么是sub_filter
官方文档说
The ngx_http_sub_module module is a filter that modifies a response by replacing one specified string by another.
也就是可以替换某些响应的信息,这里处理修改host防止发生跳转并将weburl中的8090设置为8080。猜测.net 服务那边拿了端口。
当然这些应该都可以通过Web Service 配置文件实现这里就不做进一步的探究了。
其中
sub_filter http://external-ip:8090/ http://expternal-ip:8080/;
用于替换WSDL调试工具中post-form内的地址
sub_filter '<soap:address location="http://extenal-ip:8090/' '<soap:address location="http://extenal-ip:8080/';
用于替换wsdl中的不对的地址
----- 更新.........
发现确实是.net soap web service会带端口回来的问题。这里转载记录别人的探究
感谢CSDN博主「brainty」
原文链接:https://blog.csdn.net/ying83811/article/details/44198597
C#中使用webservice接口的时候,返给服务器的IP地址是带上了端口号的。但是有时候不能要那个端口(比如用nginx做了转发),就需要在服务端处理一下(处理内容就是后面的代码)。此外,需要在配置文件中web.config中的system.web中添加一些东西:
<webServices>
<protocols>
<add name="HttpGet"/>
<add name="HttpPost"/>
<add name="HttpSoap"/>
</protocols>
<soapExtensionReflectorTypes>
<add type="CommMethod.OuterPortReflector,CommMethod"/>
</soapExtensionReflectorTypes>
</webServices>
注:1.type内容是类名,包名。这一点和msdn上的那个人写的有些不同(有可能是版本的问题)(http://blogs.msdn.com/b/kaevans/archive/2005/11/16/493496.aspx)。
2.如果没有protocols中的内容的话,有可能post和get请求不能被正确识别(未做过验证,只是在博客园上看见过类似问题)。
3.stackoverflow源地址:http://stackoverflow.com/questions/1531448/asp-net-web-service-changes-port-on-invoke
————————————————
代码:
//-----------------------------------------------------------------------
// <copyright file="OuterPortReflector.cs" company="">
// * Copyright (C)
// * version :
// * author : ying83811
// * FileName: OuterPortReflector.cs
// * history : created by ying83811
// </copyright>
//-----------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Services.Description;
namespace Better517Na.KoreaProductInterface.CommMethod
{
/// <summary>
/// OuterPortReflector类
/// </summary>
public class OuterPortReflector : SoapExtensionReflector
{
/// <summary>
/// 重写ReflectMethod
/// </summary>
public override void ReflectMethod()
{
}
/// <summary>
/// 重写ReflectDescription
/// </summary>
public override void ReflectDescription()
{
// 为了说明问题,这里直接把端口号写死了,建议写在配置文件中
string portNum = "8888";
portNum = ":" + portNum;
ServiceDescription description = ReflectionContext.ServiceDescription;
foreach (Service service in description.Services)
{
foreach (Port port in service.Ports)
{
foreach (ServiceDescriptionFormatExtension extension in port.Extensions)
{
SoapAddressBinding binding = extension as SoapAddressBinding;
if (null != binding)
{
binding.Location = binding.Location.Replace(portNum, string.Empty);
}
else
{
HttpAddressBinding httpBinding = extension as HttpAddressBinding;
if (httpBinding != null)
{
httpBinding.Location = httpBinding.Location.Replace(portNum, string.Empty);
}
else
{
Soap12AddressBinding soap12Binding = extension as Soap12AddressBinding;
if (soap12Binding != null)
{
soap12Binding.Location = soap12Binding.Location.Replace(portNum, string.Empty);
}
}
}
}
}
}
}
}
}
本文为Lokie.Wang原创文章,转载无需和我联系,但请注明来自lokie博客http://lokie.wang