Your browser (Internet Explorer 6) is out of date. It has known security flaws and may not display all features of this and other websites. Learn how to update your browser.
X
Aside

hCaptcha on OwnCloud

A couple of days back I logged into CloudFlare and noticed that they are using a new captcha system on the login page, hCaptcha.

Now if you have been on the internet long enough, you would have encountered Google’s reCaptcha (from CAPTCHA – Completely Automated Public Turing test to tell Computers and Humans Apart), that annoying pop-up where you either need to type in some squiggly text (last time), click a bunch of picture or just click a checkbox before you can submit that funny cat photo. This is to prove that you are really a human posting the above-mentioned cat photo and not some bot trying to spam or probe the funny cat website.

The idea of hCaptcha is to reduce the footprint of Google on users, considering they have their finger in pretty much every pie. Supposedly, hCaptcha captures a minimal amount of user information since they are not interested in advertising or selling personal data. They tout that they have a better experience but as of now, that doesn’t seem to be the case, since I trigger the captcha pretty much all the time… (Maybe I am a bot…) But I believe as more users use the service, they should be able to better tell bots from humans.

Now back to the meat of this post. After seeing Cloudflare’s switch to hCaptcha, I figured I could make use of CAPTCHAs to reduce the impact of bots on the services I have exposed to the internet, such as WordPress here and Owncloud and a few other services. Since I’m the main user of the services, it doesn’t frustrate me to click on CAPTCHAs. Besides, for every CAPTCHA solved, I get paid (though pretty much next to nothing :P)

WordPress was pretty easy since there is already a plugin developed by the hCaptcha and the community.

Next was to add hCaptcha in the OwnCloud service that I am running. This is where my problem arise. Apparently, not many people have done CAPTCHA integration on Owncloud, since I couldn’t find much resource online. The only one I found was this github repo by a Taiwanese IT Service Provider. However, it seems like they the are self-hosting the reCaptcha javascript and validating the somewhere using javascript. Problem is, I’m not a developer, much less a JS developer, so for the life of me, I can’t tell how they are validating the CAPTCHA with reCaptcha. Also, they are self-hosting reCaptcha code, so if they are any updates, they will have to manually update the JS file. Good for air-gapped network, not so good for lazy people like me. So, taking reference from that repo and also the hCaptcha blog post on PHP integration , I made my own changes to OwnCloud to enable hCaptcha. Here are the steps to save you some frustration and hours.
*Disclaimer: I am a systems administrator by trade and not a developer. What I lack in coding skills, I make up in hacking things to work. So my solution will be very ugly to PHP developers out there. Also, I’m making changes to OwnCloud core files, so the next update, *poof* all the customisations will be gone.

First things first, sign up for a hCaptcha account and take note of the site key and secret key. Guard your secret key and don’t expose it on any public facing page/script.

Next is to add hCaptcha to the login, this step is pretty simple, just add two lines of HTML to login.php
Take note to input the site key from hCaptcha.
I’ve placed the hCaptcha button after the <fieldset> stanza so as not to mess up the existing CSS.

<?php /** @var $l \OCP\IL10N */ ?>
<?php
vendor_script('jsTimezoneDetect/jstz');
script('core', [
        'visitortimezone',
        'lostpassword',
        'login',
        'browser-update'
]);
?>

<!-- Add hCaptcha JavaScript Library -->
<script src='https://www.hCaptcha.com/1/api.js' async defer></script>
<!--[if IE 8]><style>input[type="checkbox"]{padding:0;}</style><![endif]-->
<form method="post" name="login">
...
        </fieldset>
        <!-- Add hCaptcha Button -->
        <div class="h-captcha" data-sitekey="SITE KEY"></div>
</form>

After adding the hCaptcha, you will find that OwnCloud wouldn’t load the hCaptcha button, this is due to the OwnCloud CSRF Policy. So the next thing is to grant the hCaptcha domain permission to load scripts. Edit the LoginController.php file to add the policy in the showLoginForm() function.

        public function showLoginForm($user, $redirect_url, $remember_login) {
...
                if (!empty($redirect_url) && ($remember_login === null) &&
                        ($this->userSession->isLoggedIn() === false) &&
                        (\strpos($this->urlGenerator->getAbsoluteURL(\urldecode($redirect_url)),
                                        $this->urlGenerator->getAbsoluteURL('/index.php/f/')) !== false)) {
                        $parameters['accessLink'] = true;
                }

                // CSRF Policy for hCaptcha
                $response = new TemplateResponse($this->appName, 'login', $parameters, 'guest');
                $csp = new ContentSecurityPolicy();
                        $csp->addAllowedImageDomain('*.hcaptcha.com');
                        $csp->addAllowedImageDomain('hcaptcha.com');
                        $csp->addAllowedMediaDomain('*.hcaptcha.com');
                        $csp->addAllowedMediaDomain('hcaptcha.com');
                        $csp->addAllowedFrameDomain('*.hcaptcha.com');
                        $csp->addAllowedFrameDomain('hcaptcha.com');
                        $csp->addAllowedStyleDomain('*.hcaptcha.com');
                        $csp->addAllowedStyleDomain('hcaptcha.com');
                        $csp->addAllowedScriptDomain('*.hcaptcha.com');
                        $csp->addAllowedScriptDomain('hcaptcha.com');
                $csp->allowInlineScript(true);

                $response->setContentSecurityPolicy($csp);
                return $response;

                //return new TemplateResponse(
                //      $this->appName, 'login', $parameters, 'guest'
                //);

Now that we can load the hCaptcha button, next is to validate the hCaptcha response during login. After performing CAPTCHA check, hCaptcha will include the h-captcha-response in form data, so we will validate this response with hCaptcha’s siteverify API. Again, edit the LoginController.php file, but this time we are interested in the tryLogin() function.
Take note to input the secret key from hCaptcha.

        public function tryLogin($user, $password, $redirect_url, $timezone = null) {
                // Check if h-captcha-response is present and validate hCaptcha response
                if(isset($_POST['h-captcha-response']) && !empty($_POST['h-captcha-response'])){
                        $data = array(
                                'secret' => "SECRET KEY",
                                'response' => $_POST['h-captcha-response']
                        );
                        $verify = curl_init();
                        curl_setopt($verify, CURLOPT_URL, "https://hcaptcha.com/siteverify");
                        curl_setopt($verify, CURLOPT_POST, true);
                        curl_setopt($verify, CURLOPT_POSTFIELDS, http_build_query($data));
                        curl_setopt($verify, CURLOPT_RETURNTRANSFER, true);
                        $verifyResponse = curl_exec($verify);
                        $responseData = json_decode($verifyResponse);

                        if($responseData->success !== true) {
                                $this->session->set('loginMessages', [
                                        ['invalidCaptcha'], []
                                ]);
                                $args = [];
                                return new RedirectResponse($this->urlGenerator->linkToRoute('core.login.showLoginForm', $args));
                        }
                }
                else {
                        $this->session->set('loginMessages', [
                                ['invalidCaptcha'], []
                        ]);
                        $args = [];
                        return new RedirectResponse($this->urlGenerator->linkToRoute('core.login.showLoginForm', $args));
                }
                $originalUser = $user;
                // TODO: Add all the insane error handling
                $loginResult = $this->userSession->login($user, $password);

Notice the ‘invalidCaptcha’ error handling? We need to code this into login.php. Edit login.php again.

                <?php if (!empty($_['accessLink'])) {
                ?>
                        <p class="warning">
                                <?php p($l->t("You are trying to access a private link. Please log in first.")) ?>
                        </p>
                <?php
        } ?>
                <?php if (!empty($_['invalidCaptcha'])) {
                ?>
                        <p class="warning">
                                <?php p($l->t("Invalid/Missing Captcha. Please try again.")) ?>
                        </p>
                <?php
        } ?>
                <?php if ($_['rememberLoginAllowed'] === true) : ?>
                <div class="remember-login-container">
                        <?php if ($_['rememberLoginState'] === 0) {
                ?>

And done! Now OwnCloud is protected with hCaptcha!

To change the look and feel of the hCaptcha button, you can play with the themes of the button.
Remember to backup the edited files so that they are not lost when you upgrade OwnCloud.

I have also shared my php files on GitHub.

Aside

EdgeOS Passwordless SSH

Having purchased the Ubiquiti EdgeRouter ERPOE-5 router awhile back, I have upgraded my home network’s capabilities as a whole.

In addition to a Web Admin UI to configure the router, there is a console port for a physical access to the router and a SSH management access via the ethernet interfaces.

In an effort to secure my router, I elected to use a 15 character password to login to the router. However, being the lazy me, I want to avoid entering the full 15 character password whenever I want to access the router.

On the Web Admin UI side, it is quite simple, as I can simply just use a password manager to manage and remember the password.
On the SSH management console though, I’ll have to copy the password from the password manager whenever I want to access through that route, which can be quite troublesome

This is where passwordless SSH comes in.

Generate the authentication key pair, using ssh-keygen on *nix or PuTTY Key Generator on Windows, and store the private key in a secure location. The public key is what will be used to store on the router.

Normally for a *nix machine, the public key usually goes into the .ssh/authorized_keys file in the user’s home directory.
On the EdgeOS though, the top of the file contains some warning about losing changes
edgeos-authorized_keys

It seems like the setting will not persist across reboots and sure enough, after the next EdgeOS software update and reboot (I love the uptime of the router!), the key was gone from the file!

A bit of googling brought me to this post in the Ubiquiti Forum: ssh authorized_keys

Now the solution only showed the use of the loadkey command, which requires uploading the public key file to the router.
Another way to do it is to use the commandline in configure mode

[email protected]:~$ configure
[email protected]# set system login user ubnt authentication public-keys <key-name> type ssh-rsa
[email protected]# set system login user ubnt authentication public-keys <key-name> key <base64 encoded public key>
[email protected]# commit
[email protected]# save

<key-name>: Arbitrary name for the key
<base64 encoded public key>: The base64 public key from PuTTY Key Generator or id_rsa.pub

Viola, now the public key will persist across reboots and will also be exported out when you backup the config.

Aside

MariaDB Memory Footprint

Recently, I’ve upgraded the database of this blog from MySQL to MariaDB.

For those of you who are not aware, MariaDB is a fork from MySQL by the original founder of MySQL.
MariaDB 5.5 is fully compatible with MySQL 5.5 and can be replaced by “dropping in” directly over MySQL.

What I noticed after upgrading to MariaDB was that the memory usage shot up to close to my VPS limit.
As my VPS has limited memory, this sudden memory increase might create problems down the road.

After investigating the possible causes, it was traced to the new database engine introduced in MariaDB, the Aria Storage Engine.

According to the Knowledge Base, the default buffer size is 128M, a pretty big number for a VPS with only 512M of available memory.
Since I’m still using the ISAM engine and have no need to use the Aria engine, it should be turned off to reduce the memory usage.
However, as the storage engine is an integral part of the DBMS, it couldn’t be turned off, so the next best thing would be to tune the config in my.cnf

[mariadb]
aria_pagecache_buffer_size = 512k
aria_sort_buffer_size = 16k

There, after tuning the buffer size to 512K and 16K, the memory usage is back to normal.

Aside

More Tritium Keychains!

Got 3 more Tritium zip markers from Traser Watches and in addition, a large kit marker.

The large kit marker is huge! And it’s very bright compared to the zip markers, I feel like I’m gonna get cancer just by looking at it… (of course that is just a joke… Tritium markers in their protective casing are harmless, but still, I wouldn’t put them in my trousers pocket, just in case)

Yellow, Orange and White Zip Markers
From Left to Right: Yellow, Orange and White zip markers
Mouse-over to see the markers in the dark

Large green kit marker compared to yellow kit marker

Aside

Embedding Certificates into OpenVPN Config

I found out a very cool configuration trick for OpenVPN while doing some read-up on OpenVPN encryption key size.

In the middle of the thread, one of the user, “300000”, posted his/her configuration settings.
The part that caught my eye was the chunk of Base64 encoded certs.

I never knew you could embed the certs directly into the config file!

All these while I’ve been using the respective keywords to define the path to the individual cert files. This have made the distribution of configuration to each user quite a pain, since in addition to the config file, I have to send them the cert and key files and also to instruct them on where to put the individual files.

Now, I can just pass them a single .ovpn file and tell them where to place it and they are good to go. No more additional steps like telling them to download the cert files and placing them in a specific directory.

To embed the certs, simply place the Base64 encoded cert text into the respective <ca> </ca>, <cert> </cert> and <key> </key> tags in your .ovpn config file and comment out the “ca”, “cert” and “key” keywords.

client
remote my-server 1194
proto udp
dev tun
persist-key
persist-tun
resolv-retry infinite
nobind
#ca ca.crt
#cert client.crt
#key client.key
comp-lzo
verb 3
<ca>
-----BEGIN CERTIFICATE-----
***Paste CA Cert Text Here***

-----END CERTIFICATE-----
</ca>
<cert>
-----BEGIN CERTIFICATE-----
***Paste Your Cert Text Here***

-----END CERTIFICATE-----
</cert>
<key>
-----BEGIN PRIVATE KEY-----
***Paste Your Cert Private Key Here***

-----END PRIVATE KEY-----
</key>

There, simple.

Aside

Why we can’t have nice things

Brainfart.SG was taken down for almost a month since last April, due to my VPS being exploited. The reason I believe is due to a misconfiguration of the webserver.

Somebody managed to install a backdoor in the VPS and then installed a script to launch a DoS attack.
My VPS was only suspended at first, but after recovering my VPS, it was again compromised to launch DoS attack. Which resulted in me being banned from BuyVM.

Since then, I have moved to Virpus and have spent a considerable effort to harden the VPS.
I’ve installed APF, rkhunter, ZB Block, among other things. And not to mention closing the security hole for nginx + PHP.
Looks like I’ll have to be on an active lookout for vulnerabilities and also solutions…

It seems like in a perfect world, you can leave your doors unlock at night and you also need not worry about your webserver much. But since we live in a imperfect world, we’ll have to lock up our doors, harden our webservers, deploy SSL for our web connections, etc.

And this is why we can’t have nice things.

Aside

Android Customisation

The awesome thing about Android phones, is the amount of customisation you can do to it, so much so that it is almost entirely a different phone from the original one you got.

HTC Desire Z with Sense UI
HTC Desire Z with Sense UI

After spending hours installing a custom ROM and fiddling with the widgets:

My Customised Homescreen
My Customised Homescreen

The only downside to this is, you need to know what’s going on and know how to fiddle with the widgets. And of course, some time to do the layout and configuration. Definitely not for the faint hearted.

In case you are wondering what are the widgets I used:

Homescreen Breakdown
Homescreen Breakdown

Aside

Email Sender Authentication

Came across a very interesting service today while trying to setup Sender Policy Framework (SPF) for my work email domain.

Port25 Solutions*, an email infrastructure software provider, has a service that helps check the sender authenticity of your email service (ie, the SPF settings, DomainKeys, etc) and also the spam rating of your email according to SpamAssassin’s settings.

Basically, it works by sending an email to this address:
[email protected]
The content of the email can be empty, or if you want to test your marketing email or newsletter for “spamminess” against a SpamAssassin filter, you can include it as the email subject and content.

After sending the email, the service will reply with a report detailing your authentication settings and the spam rating of the email that you have sent.

The is a truncated report of my domain before implementing SPF:

This message is an automatic response from Port25's authentication verifier
service at verifier.port25.com.  The service allows email senders to perform
a simple check of various sender authentication mechanisms.  It is provided
free of charge, in the hope that it is useful to the email community.  While
it is not officially supported, we welcome any feedback you may have at
<<a href="mailto:[email protected]">[email protected]</a>>.

Thank you for using the verifier,

The Port25 Solutions, Inc. team

==========================================================
Summary of Results
==========================================================
SPF check:          neutral
DomainKeys check:   neutral
DKIM check:         neutral
Sender-ID check:    neutral
SpamAssassin check: ham

==========================================================
Details:
==========================================================

HELO hostname:  mail.brainfart.sg
Source IP:      209.141.57.235
mail-from:      <a href="mailto:[email protected]">[email protected]</a>

----------------------------------------------------------
SPF check details:
----------------------------------------------------------
Result:         neutral (SPF-Result: None)
ID(s) verified: <a href="mailto:[email protected]">[email protected]</a>
DNS record(s):
    brainfart.sg. SPF (no records)
    brainfart.sg. TXT (no records)

----------------------------------------------------------
DomainKeys check details:
----------------------------------------------------------
Result:         neutral (message not signed)
ID(s) verified: <a href="mailto:[email protected].sg">[email protected]</a>
DNS record(s):

----------------------------------------------------------
DKIM check details:
----------------------------------------------------------
Result:         neutral (message not signed)
ID(s) verified:

NOTE: DKIM checking has been performed based on the latest DKIM specs
(RFC 4871 or draft-ietf-dkim-base-10) and verification may fail for
older versions.  If you are using Port25's PowerMTA, you need to use
version 3.2r11 or later to get a compatible version of DKIM.

----------------------------------------------------------
Sender-ID check details:
----------------------------------------------------------
Result:         neutral (SPF-Result: None)
ID(s) verified: <a href="mailto:[email protected]">[email protected]</a>
DNS record(s):
    brainfart.sg. SPF (no records)
    brainfart.sg. TXT (no records)

----------------------------------------------------------
SpamAssassin check details:
----------------------------------------------------------
SpamAssassin v3.3.1 (2010-03-16)

Result:         ham  (-0.0 points, 5.0 required)

 pts rule name              description
---- ---------------------- --------------------------------------------------
-0.0 T_RP_MATCHES_RCVD      Envelope sender domain matches handover relay
                            domain
-0.0 BAYES_40               BODY: Bayes spam probability is 20 to 40%
                            [score: 0.3966]
 0.0 HTML_MESSAGE           BODY: HTML included in message

And this is after implementing SPF:

<pre>This message is an automatic response from Port25's authentication verifier
service at verifier.port25.com.  The service allows email senders to perform
a simple check of various sender authentication mechanisms.  It is provided
free of charge, in the hope that it is useful to the email community.  While
it is not officially supported, we welcome any feedback you may have at
<<a href="mailto:[email protected]">[email protected]</a>>.

Thank you for using the verifier,

The Port25 Solutions, Inc. team

==========================================================
Summary of Results
==========================================================
SPF check:          pass
DomainKeys check:   neutral
DKIM check:         neutral
Sender-ID check:    pass
SpamAssassin check: ham

==========================================================
Details:
==========================================================

HELO hostname:  mail.brainfart.sg
Source IP:      209.141.57.235
mail-from:      <a href="mailto:[email protected]">[email protected]</a>

----------------------------------------------------------
SPF check details:
----------------------------------------------------------
Result:         pass
ID(s) verified: <a href="mailto:[email protected]">[email protected]</a>
DNS record(s):
    brainfart.sg. SPF (no records)
    brainfart.sg. 86400 IN TXT "v=spf1 mx -all"
    brainfart.sg. 86400 IN MX 10 mail.brainfart.sg.
    mail.brainfart.sg. 85429 IN A 209.141.57.235

----------------------------------------------------------
DomainKeys check details:
----------------------------------------------------------
Result:         neutral (message not signed)
ID(s) verified: <a href="mailto:[email protected]">[email protected]</a>
DNS record(s):

----------------------------------------------------------
DKIM check details:
----------------------------------------------------------
Result:         neutral (message not signed)
ID(s) verified:

NOTE: DKIM checking has been performed based on the latest DKIM specs
(RFC 4871 or draft-ietf-dkim-base-10) and verification may fail for
older versions.  If you are using Port25's PowerMTA, you need to use
version 3.2r11 or later to get a compatible version of DKIM.

----------------------------------------------------------
Sender-ID check details:
----------------------------------------------------------
Result:         pass
ID(s) verified: <a href="mailto:[email protected]">[email protected]</a>
DNS record(s):
    brainfart.sg. SPF (no records)
    brainfart.sg. 86400 IN TXT "v=spf1 mx -all"
    brainfart.sg. 86400 IN MX 10 mail.brainfart.sg.
    mail.brainfart.sg. 85429 IN A 209.141.57.235

----------------------------------------------------------
SpamAssassin check details:
----------------------------------------------------------
SpamAssassin v3.3.1 (2010-03-16)

Result:         ham  (-1.9 points, 5.0 required)

 pts rule name              description
---- ---------------------- --------------------------------------------------
-0.0 T_RP_MATCHES_RCVD      Envelope sender domain matches handover relay
                            domain
-1.9 BAYES_00               BODY: Bayes spam probability is 0 to 1%
                            [score: 0.0000]
 0.0 HTML_MESSAGE           BODY: HTML included in message

Pretty nifty eh?

And there is another use for this service that I can foresee, testing end-to-end email connectivity.
After setting up a new email server, you can use this automated service for mail flow testing, sending and receiving of email. And at the same time test your SPF settings.
Cool, ain’t it!

*Note: I am in no way affiliated with Port25 Solutions, I just found this service useful and thought I should share it

Aside

Radioactive Illumination

A long while back, I bought a Tritium Kit Marker/Keychain from DealExtreme (man, that site sells everything! or so I thought…)

For those who are unaware of what Tritium is, it is a radioactive isotope of Hydrogen and the keychain uses that to excite a phosphor coating to create light in a process called radioluminescence. In short, it doesn’t require any external batteries or charging and will remain lit for as long as the radioactive ‘fuel’ is still decaying.
Now, before you panic with Chernobyl and Fukushima in your mind, you have to understand that Tritium decays by emitting beta particles. And if you still remember your Secondary School/High School physics, you’ll remember that beta particles can be stopped by a sheet of aluminum or a thick piece of plastic. In this case, the Tritium vial is encased in a thick piece of plastic, acrylic I believe, so it is pretty safe. But then again, I wouldn’t really put the kit marker in my side pockets, just in case.

Anyway, since then I’ve given the kit marker away and was looking to get some more. So where else to look for other than DealExtreme?
Turns out, DX stopped selling them awhile back… A quick forum search shows that they’ve been restricted by Paypal. Something to do with shipping radioactive items to the US perhaps? Basically, all traces of the Tritium Kit Markers vanished from the site, except for some reviews. I was quite bummed by that, until I found a UK seller on eBay, Traser Watches, selling the kit markers. The great thing about the seller is that they sell a lot more colours than DX and the pricing is fixed for all the colours. Yay!
In addition, they sell the medium and large version of the kit markers. Double-Yay!

So I ordered 3 of the kit markers (Red, Green and Blue) last Monday morning, it was shipping that Monday afternoon and arrived on Friday.
Fast shipping, I like!

Tritium Kit Markers
Tritium Kit Markers

It seems like the green marker is brighter than the one I got from DX. From a fresher batch perhaps?
Now to decide on where to place these kit markers and maybe order the larger ones from Traser Watches.
And since I’m hooked onto this Tritium illumination thingy,  maybe finally get a Ball Watch. 😀

Aside

Cape Verde

Just got back from a business trip to Cape Verde. In case you are wondering, Cape Verde is a group of islands off the coast of Senegal in West Africa.

Boy, it is a beautiful country! Totally not what I was expecting, after the trip to Tanzania in the middle of the year. The only bad thing is that it is just too damn far from Singapore… It took me some 40 hours to get to their capital, Praia and another 30 hours to get back to Singapore from Praia. The reason for the the extra 10 hours to get there? I had to layover for almost 12 hours on another island, Sal, as there wasn’t a direct flight that day… So yup, I slept like a hobo in the airport.

A pretty uneventful biz trip, just some minor hiccups here and there, no biggie. This is the type of biz trip I prefer, not much surprises and things going to plan. Would like to have some free time to go explore around though. But you can’t have everything 😉