Openconnect and Active Directory Certificate Service

Previously my openconnect server deployment plan utilizes PAM authentication (via Kerberos/Active Directory) as the primary authentication method. It works but it’s complicated (password every time). I just enabled certificate authentication today and it worked fine.

Things to note

  • Enable certificate authentication as an alternative authentication method (up to you, but some guys in our domain don’t use certificate-capable device)
  • Use “Smartcard Logon” certificate template with subject information in “Common Name” style
  • Set OID 2.5.4.3 as user identifier in openconnect server configuration
  • Provision root CA, CRL and OCSP (CRL and OCSP are optional but essential as part of the best-practice)

Something else

I provisioned the same certificate in my Yubikey PIV and TPM-based virtual smartcard, but neither works for AnyConnect client. Certificate in user certificate store is fine.

AnyConnect client refused to use smartcard
AnyConnect client refused to use smartcard

A Simple Naïve ™ Guide to ASP.NET Core Linux Deployment

Step 1: Prepare .NET Core environment

This step is absolutely easy on Ubuntu/Debian and other officially supported distributions. If you are using Archlinux, go to AUR for .NET Core runtime.

Step 2: Prepare files.

In local Visual Studio or other development environment, publish project to a folder. (dotnet build -c Release)

Copy files.

Step 3: Setting services

I wrote a simple systemd service for my application:

[Unit]
Description=A certain ASP.NET Core application
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/opt/imbushuo/somepath
ExecStart=/usr/bin/dotnet /opt/imbushuo/somepath/App.dll --server.urls=http://localhost:5050
Restart=on-failure
RestartSec=5
Environment="ASPNETCORE_ENVIRONMENT=Production"

[Install]
WantedBy=multi-user.target

Start it.

Step 4: Setting up reverse proxy

Refer to your frontend server documentation for details.

Some hints:

If you are using per-environment configuration file, make sure the configuration starts with capital letter, like appsettings.Production.json . Otherwise, the Startup class will not load the settings file.

If you want to run multiple applications, make sure add configuration class in Program class and apply it. Then, pass server.urls parameter with address and port, like what I wrote above.

The following Program.cs has been modified to enable parameter support. Feel free to copy it:

using System.IO;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;

namespace HomePortal
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var configuration = new ConfigurationBuilder()
            .AddCommandLine(args)
            .Build();

            var host = new WebHostBuilder()
                .UseKestrel()
                .UseContentRoot(Directory.GetCurrentDirectory())
                .UseConfiguration(configuration)
                .UseIISIntegration()
                .UseStartup<Startup>()
                .Build();

            host.Run();
        }
    }
}

Rule-based Routing & Traffic Forwarding with IPsec Site to Site VPN and Linux

This article is adapted from https://www.v2ex.com/t/180070 and http://hjc.im/shi-yong-strongswanda-jian-ipsecikev2-vpn/. The major difference is ShadowVPN is replaced by StrongSwan IPsec VPN in this article.

Readiness Check

  • Upgrade your staging/production environment to the latest version. Make sure all security patches are installed.
  • Make sure you have packages libpam0g-dev libssl-dev make gcc installed.

Building StrongSwan

Download the latest version here: http://download.strongswan.org/strongswan.tar.gz

Unarchive it, and configure using the following params:

./configure  --enable-eap-identity --enable-eap-md5 
--enable-eap-mschapv2 --enable-eap-tls --enable-eap-ttls --enable-eap-peap  
--enable-eap-tnc --enable-eap-dynamic --enable-eap-radius --enable-xauth-eap  
--enable-xauth-pam  --enable-dhcp  --enable-openssl  --enable-addrblock --enable-unity  
--enable-certexpire --enable-radattr --enable-tools --enable-openssl --disable-gmp --enable-kernel-libipsec

We have to specify routing table’s priority on client server(not IPsec Access Server) since we wants to specify routing table manually: –with-routing-table-prio=32800.  Also, TAP/TUN device is enabled instead of StrongSwan’s own kernel module. It will simplify the configuration later.

Then make and install it.

Configure IPsec Access Server

Just a reminder, if you have any issues about IP range, please refer to the demo topology graph. The image is unavailable right now for some reason. I’ll fix it ASAP.

Go to /usr/local/etc. Edit ipsec.secrets:

: PSK "<IPsec PRE SHARED KEY, PLEASE REMEMBER TO REPLACE IT WITH YOU OWN KEY>"
s2s : XAUTH "<ANY PASSWORD YOU WANT, PLEASE REMEMBER TO REPLACE IT WITH YOU OWN PASSWORD>"

Go to /usr/local/etc. Edit ipsec.conf:

config setup
    uniqueids=never 

conn s2sbj1_xauth_psk
    keyexchange=ikev1
    left=%defaultroute
    leftauth=psk
    leftsubnet=0.0.0.0/0
    right=%any
    rightauth=psk
    rightauth2=xauth
    rightsourceip=100.11.2.0/24
    auto=add

Go to /usr/local/etc. Edit strongswan.conf:

 charon {
         load_modular = yes
         duplicheck.enable = no
         compress = yes
         plugins {
                 include strongswan.d/charon/*.conf
         }
         # In China, please consider about replacing 8.8.8.8/8.8.4.4 to 114.114.114.114. They do offer correct DNS query results outside mainland China, as long as you have configured the Chinese routing exception for it(route to non-mainland China outbound server)
         dns1 = 8.8.8.8
         dns2 = 8.8.4.4
         nbns1 = 8.8.8.8
         nbns2 = 8.8.4.4
 }
 include strongswan.d/*.conf

Turn on IPv4 forwarding in sysctl.conf.

Edit iptables. The following configuration is for Ubuntu 14.04 LTS. For other Linux distro, check out its documentation.

iptables -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -s 100.11.0.0/24  -j ACCEPT
iptables -A FORWARD -s 100.11.1.0/24  -j ACCEPT
iptables -A FORWARD -s 100.11.2.0/24  -j ACCEPT
iptables -A INPUT -i eth0 -p esp -j ACCEPT
iptables -A INPUT -i eth0 -p udp --dport 500 -j ACCEPT
iptables -A INPUT -i eth0 -p tcp --dport 500 -j ACCEPT
iptables -A INPUT -i eth0 -p udp --dport 4500 -j ACCEPT
iptables -A INPUT -i eth0 -p udp --dport 1701 -j ACCEPT
iptables -A INPUT -i eth0 -p tcp --dport 1723 -j ACCEPT
iptables -A FORWARD -j REJECT
iptables -t nat -A POSTROUTING -s 100.11.0.0/24 -o eth0 -j MASQUERADE
iptables -t nat -A POSTROUTING -s 100.11.1.0/24 -o eth0 -j MASQUERADE
iptables -t nat -A POSTROUTING -s 100.11.2.0/24 -o eth0 -j MASQUERADE

Save it

iptables-save > /etc/iptables.rules
cat > /etc/network/if-up.d/iptables<<EOF
#!/bin/sh
iptables-restore < /etc/iptables.rules
EOF
chmod +x /etc/network/if-up.d/iptables

Configure IPsec client

Suppose you have the correct StrongSwan with TAP/TUN and routing table priority installed.

Go to /usr/local/etc, edit ipsec.secrets, just put what you have in the previous step.

Go to /usr/local/etc, edit ipsec.conf:

config setup
    uniqueids=never 
    strictcrlpolicy=no
    

conn s2sbj1
    keyexchange=ikev1
    ikelifetime=1440m
    keylife=120m
    # Enable this will cause authentication failure
    aggressive=no
    ike=aes-sha2-modp2048
    esp=ase-sha2
    xauth=client
    left=<eth0's IP address>
    # Ask your server
    leftsourceip=%config
    leftauth=psk
    leftauth2=xauth
    rightauth=psk
    rightauth2=xauth
    right=<Your IPsec VPN Server's public IP address>
    # For Microsoft Azure and other service providers who use SNAT, specify that to prevent IKE_SA failure
    rightid=%any
    xauth_identity=s2s
    auto=add
    rightsubnet=0.0.0.0/0

Establish Connection

On your IPsec VPN server, type sudo ipsec start .

On your client server, type:

sudo ipsec start
sudo ipsec up s2sbj1

It should get connected shortly. Go to ifconfig and you should find a new network adapter called ipsec0.

Configure rule-based routing

Create a new routing table.

user@ibntwkstgepbj1:~$  sudo vim /etc/iproute2/rt_tables
200 bj1s2s
:q
user@ibntwkstgepbj1:~$

Get the routing configuration in table 220 (IPsec table).

user@ibntwkstgepdm1:~$  sudo ip route list table 220
default dev ipsec0  proto static  src 100.11.2.1
42.159.66.233 via 10.0.0.1 dev eth0  proto static  src 10.0.0.4

Specify the default route for this table (copy it from 220):

user@ibntwkstgepdm1:~$  sudo ip route add default dev ipsec0  proto static  src 100.11.2.1 table bj1s2s

(You don’t have to copy the second line I guess, but I added that)

Add IP rules.

user@ibntwkstgepdm1:~$  ip rule add from <IP Range> table bj1s2s

Refresh routing table.

user@ibntwkstgepdm1~$  ip route flush cache

Compose a shell script if you want to compelte that automatically for every reconnection.

Conclusion

We implemented a simple line optimization using rule-based routing in this example. For application-based service, you are all set and ready to go. For VPN access services, configuration for iptables is needed in order to tag data packets and route them correctly. Check out this article for more details.

I didn’t offer a auto routing script in this example. I strongly recommend you to write it since it saves your time by configuring routing table automatically.

For multiple IPsec connections and routings, just specify the source IP, which is 100.11.2.1 and 100.21.2.1 in routing tables. They use the same adapter.

面朝HTTPS,春暖花开

从今天起,做一个有证书的人,

加密,解密,保证安全

从今天起,关系PKI体系和TLS连接

我有一个证书,面朝HTTPS,春暖花开

本站现已支持HTTPS连接。稍后在配置后将全站强制HTTPS。

Linode大法好 (Linode is just…..awesome!)

呐,整个站迁移到Linode上了。果然访问快了好多好多好多。Linode大法好,早日摆脱共享主机早日获得新生。

需要注意几个事情:

  • Linode的年付优惠我已经找不到了。
  • 日本机房不一定好。我选的是Fremont。
  • Ubuntu Server 14.04 LTS装了php5后需要手动给apache的模块赋执行权限
  • 注意wp-content的权限 (Solved.看下面)
  • 建议2GB以下打开swap
  • (by David Huang)防范DDoS。如果把swap关掉,把mysql的oom_score调到0
  • 不建议搞ftp,要搞iptables做好。如果权限正确更新插件不需要ftp。
  • 把Google Fonts Link换掉。这个搜索一下。不止一个Open Sans,还有Source Code Pro。
  • 2014.7.12 Update 给wp-content赋执行权限,否则会403。

然后这是我的邀请码(就当是资助我吧:https://www.linode.com/?r=88e97b8895dd86f1dc509451440604fc8c313e85

DON’T verify CAPTCHA by JavaScript

昨天中考成绩出来了。早在模拟填报志愿的时候,我们很多同学就已经发现了验证码很难完全显示。那时然后我淡定地打开Chrome的Dev Tools,查看DOM发现了一些神奇的东西。(回家是IE11)

Screenshot (171)

So, you MEAN this is CAPTCHA? WTF….

Therefore, I can EASILY parse the document, submit form, and get all the informaton I want.

Screenshot (178)

然后继续看流量。发现整个过程是明文的, including password.

Screenshot (172)

What’s more, the verification process is completed in the client side…(later I found that I could bypass the CAPTCHA by sending the HTTP request directly.)

Screenshot (174)

By using JSESSIONID, I can acquire the result(a webpage).

Then parse it, and get the final result.

Later that night(~10:20 6.21.14), I started writing the program(using C#).

Then I have a result sheet.

CONCLUSIONS

在客户端校验验证码是非常非常非常危险的(这句话很重要所以说三遍),而且Script不做混淆,业务逻辑直接暴露在客户端更加危险。

第二,Unit Testing不认真做,不是所有代码路径都得到了测试,后果很难预料。(我猜这是Behavior-Driven Development instead of Test-Driven Development

第三,都2014年了你还是XP样式还不支持IE11你好意思吗。。。。

Screenshot (180)