再次利用nginx反向代理发送邮件隐藏源站IP

越来越发觉nginx是个神器,从上次隐藏回调IP,现在再次利用它来隐藏邮件发送的源站IP!

这两天网站加了CDN,目的是隐藏源站IP,现在问题来了,前置CDN解决了IP暴露问题,但是对于使用邮件注册会员的系统来说,就产生了IP暴露的问题,我们来看看是怎么回事

我使用的是QQ域名邮箱,显示邮件原文后就可以看到源站IP,这不是直接脱了裤子让人家打吗,问题总是需要解决的,研究了下nginx的用法,发现nginx可以TCP反代,这可是好东西啊!

先设置源站的nginx配置文件

stream {
upstream mail.com {
server 172.16.110.13:465 weight=1;
server 172.16.110.12:465 weight=1;
server 172.16.110.14:465 weight=1;
}

server {
    listen       465;
    proxy_pass   mail.com;
}

}

然后设置源站的hosts文件

127.0.0.1 mail.com

最后设置3台代理服务器的nginx配置

stream {
server {
listen 465;
proxy_pass smtp.qq.com:465;
}
}

因为使用的是SSL,采用465端口,自己看就明白了,举一反三,其他端口应该也差不多!

邮件配置

email.host=mail.com
email.port=465
email.username=service@umistrong.com.cn
email.password=password
email.from=service@umistrong.com.cn

最后贴一下我用的邮件发送工具类,是SSL版本的


import java.security.GeneralSecurityException;
import java.util.; import javax.mail.;
import javax.mail.internet.*;
import com.sun.mail.util.MailSSLSocketFactory;
public class EmailUtils {

private static String host = PropertiesUtils.getProperties().getProperty("email.host");
private static String port = PropertiesUtils.getProperties().getProperty("email.port");
private static String userName = PropertiesUtils.getProperties().getProperty("email.username");
private static String password = PropertiesUtils.getProperties().getProperty("email.password");
private static String from = PropertiesUtils.getProperties().getProperty("email.from");

public static void sendHTMLEmail(String to,String subject,String content) throws GeneralSecurityException{
    // 获取系统属性
    Properties properties = System.getProperties();

    // 设置邮件服务器
    properties.setProperty("mail.smtp.host", host);
    properties.put("mail.smtp.port", port);

    properties.put("mail.smtp.auth", "true");
    MailSSLSocketFactory sf = new MailSSLSocketFactory();
    sf.setTrustAllHosts(true);
    properties.put("mail.smtp.ssl.enable", "true");
    properties.put("mail.smtp.ssl.socketFactory", sf);
    // 获取默认session对象
    Session session = Session.getDefaultInstance(properties,new Authenticator(){
        public PasswordAuthentication getPasswordAuthentication()
        {
            return new PasswordAuthentication(userName,password); //发件人邮件用户名、密码
        }
    });

    try{
        // 创建默认的 MimeMessage 对象
        MimeMessage message = new MimeMessage(session);

        // Set From: 头部头字段
        message.setFrom(new InternetAddress(from));

        // Set To: 头部头字段
        message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));

        // Set Subject: 头部头字段
        message.setSubject(subject);

        // 设置消息体
        message.setContent(content,"text/html; charset=utf-8");

        // 发送消息
        Transport.send(message);
    }catch (MessagingException mex) {
        mex.printStackTrace();
    }
}
}

这样搞完以后,对原先支付系统无需任何改动,只需要改动配置文件的邮件发送服务器地址即可,负载均衡发邮件,美滋滋!!!

收工睡觉,哈哈哈!

利用nginx实现支付系统隐藏IP进行回调

之前开发了一套聚合支付系统——优米云支付https://pay.umistrong.com.cn/

虽然目前系统没有遭遇DDOS攻击,但是还是需要未雨绸缪,避免未来可能发生的攻击,对云服务器隐藏IP是有必要的。

我们都知道,网站前置CDN进行IP隐藏很容易,但是对于支付系统这类需要对商户网站进行回调,由于是用本系统发起对商户网站的http请求,自然会有IP暴露的问题。

实现隐藏IP有3个思路

方案1.使用apache的httpclient进行代理访问

    //设置代理IP、端口、协议(请分别替换)
    HttpHost proxy = new HttpHost("你的代理的IP", 8080, "http");

    //把代理设置到请求配置
    RequestConfig defaultRequestConfig = RequestConfig.custom()
            .setProxy(proxy)
            .build();

    //实例化CloseableHttpClient对象
    CloseableHttpClient httpclient = HttpClients.custom().setDefaultRequestConfig(defaultRequestConfig).build();

    //访问目标地址
    HttpGet httpGet = new HttpGet("http://www.baidu.com");

    //请求返回
    CloseableHttpResponse httpResp = httpclient.execute(httpGet);
    try {
        int statusCode = httpResp.getStatusLine().getStatusCode();
        if (statusCode == HttpStatus.SC_OK) {
            System.out.println("成功");
        }
    } catch (Exception e) {

    } finally {
        httpResp.close();
    }

第一种方案,需要在每个代理服务器安装代理软件,并且有多台代理时候,依赖支付系统内轮询做负载均衡。

方案2.开发扩展模块,支付系统调用扩展模块接口进行通信

第二种方案,扩展模块需要部署到每个代理服务器,假设扩展模块用java开发,就需要每台服务器安装JRE,也很麻烦,负载均衡可在支付系统做也可在扩展模块做。

方案3.使用nginx的反向代理,在java发起请求时候,自定义header携带网址参数,nginx端设置proxy_pass 使用获取到的header参数即可

第三种方案就简单了,依靠nginx自带的负载均衡,本文重点说的这个方案,非常灵活!!!

java代码部分,增加X-Target的header

URL url = new URL("hidden.com");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestProperty("X-Target", requestUrl);//requestUrl为商户网站回调地址

hosts文件设置本地解析,支付系统和nginx负载均衡放同一服务器上

127.0.0.1 hidden.com

nginx负载均衡端配置underscores_in_headers必须开,否则nginx无法接收自定义header,proxy_set_header X-Target也要加,这个需要向下级nginx传递header,nginx获取自定义header的写法$http_前缀加上名称小写且中划线变成下划线,这里upstream我用了三台服务器,权重都是1,平均分配

http {
	underscores_in_headers on;
	
	upstream hidden.com {
		server 172.16.110.13:80 weight=1;
		server 172.16.110.12:80 weight=1;
		server 172.16.110.14:80 weight=1;
	}
	
	server {
        	listen       80;
        	server_name  hidden.com;

       	 	location / {
			proxy_set_header X-Target $http_x_target;
        		proxy_pass   http://hidden.com;
        	}
	}
}

nginx代理端配置, resolver一定要加,不然会出现502错误

	server {
        	listen       80;
        	server_name  hidden.com;
        	resolver     8.8.8.8;

        	location / {
           		 proxy_pass   $http_x_target;
        	}
	}

至此配置完成,后续增加代理服务器就很方便了,可以在负载均衡端增加节点,或者在代理服务器下继续传递X-Target,理论上是无限级传递。