Captchas are commonly used in websites when submitting a form, uploading files or in general when sending data in order to verify that the sender is not a robot. There are lots of captchas. Google has its own, Google Recaptcha. Google Recaptcha works with public and secret keys between the server and client side in order to verify the user.
When you apply for a Google Recaptcha key pair, Google asks you to link these keys with a domain (or a number of domains). When you want to use Google Recaptcha in your own website this is Ok. However, if you are a plugin developer and you want to include Google Recaptcha in your plugin, then you have a problem because you do not know the domain that is going to be installed. It turns out that you have to instruct your customers (users of the plugin) to create a Google account (if they don’t have any) and get Google keys for their domain. Not all customers want to do that.
As a work-around, Google in its first implementation of Google Recaptcha offered global keys to developers, that is keys that worked for all domains. This allowed developers to include it in their plugins and Google Recaptcha became very popular. However, it also became very hard to solve. In the battle against robots, Google made its captcha so difficult, that users started complaining and eventually it became user-unfriendly and impractical.
So Google released version 2 of Google Recaptcha which uses a different technique to fight robots and it is by far faster, safer and user friendly. Again, you need to get key pairs and link them with your domain to make it work. Unfortunately Google stopped supporting global keys for its new captcha, so plugin developers are forced to request from their customers to have a Google account and get their own keys from Google.
However there is a work-around to this. The following procedure, although somehow complex, will show you how to implement the new Google Recaptcha in your plugin without the need of asking your customers to have Google accounts or keys. It is effective and secure.
The main idea is that Google Recaptcha is not generated in the user s domain, but it is always generated in your own web server using your public and secret keys and it is served in the user though an iframe. This means that you need to have a web server to serve requests of your plugin users. Though this might sound simple, there are lots of issues that need to be addressed correctly so that security is preserved (after all this is why we use captchas) and captcha functionality is as expected.
The issues that we need to address are the following:
- How captcha is securely implemented?
- The domain that the iframe uses to implement the captcha is different than the user s domain. This means that exchange of data between the captcha and the user is prohibited. So, how the user knows that the captcha has been completed, or how he gets notified if the captcha has expired, or how the user can reset the captcha?
- The iframe does not resize as Google Recaptcha resizes some times to show additional features (such as prompt the user to type a text or select from a number of images). This means that some captcha features may be cropped and not shown to the user, which may make the captcha unusable.
Server Sides and Client Sides
In order to understand how this procedure works, we first need to understand the sides that are involved.
- As previously mentioned, the captcha will be generated in the plugin developer s web server, so first we have the developer s server side (DEV-SS).
- A developer s customer uses the plugin in its own website to offer it to its users. So whenever a user opens the website, the customer s web site generates the plugin, together with the captcha, in the customer s web server, which is the website server side (WEB-SS).
- The plugin is served to the customer s user, which interacts with it and with the captcha, at the website client side (WEB-CS).
Most common web servers that people use to create their websites offer one-way communication with the users. This means that the user (client-side) requests something from the website (server-side) and the website responds (e.g. request to open a web page). The opposite cannot happen; the server cannot request something from the user.
Whenever a user opens a web page, a unique session is created between the user and the website. Sessions store information about the identity of the user and it is a secure and effective way of verifying the user. When the user closes its browser or has not interaction with the website for a long time, session is reset, so no sensitive data are kept (that could be exploited by hackers).
Session variables are used by the present procedure to secure the communication between the various sides and avoid hacking.
Captcha is generated in DEV-SS. So when the developer s plugin, which has been installed by a customer in its website (WEB-SS) and invoked by a customer s user that opens the website in its browser (WEB-CS) needs to generate the captcha, it must request it from DEV-SS. The simplest solution would be the plugin to generate an iframe and just point its url in DEV-SS that returns the captcha html code, e.g.
The captcha is generated in an iframe that belongs to developer s domain, so it requires the keys of the developer s domain and not the keys of the website domain. So, regardless of the website domain and whether the developer s customer has a Google account and has acquired Google Recaptcha keys for its domain, it will always be generated.
The above procedure describes visually the basic idea of implementing the new Google Recaptcha without keys; however there are still a lot of things that need to be done.
Google Recaptcha uses a pair of public and secret keys in order to verify that captcha was solved in a secure manner, without exposing sensitive information to the client-side, which is vulnerable to hackers. The same must also be applied here, so that security is preserved, however we need to understand how exactly Google Recaptcha works and what are the dangers lurking.
The client-side is the browser of the user who opens a website page and interacts with its contents. Client-side is considered to be vulnerable to hackers. Any information kept in browser s memory or in cookies can be stolen. So, we must ensure that no sensitive information is kept in the browser.
The server-side is the place where the website is installed. All sensitive information is kept in the web server, and web servers take many measures for protecting themselves against hackers.
Suppose that the user wants to fill-in a form and submit it to the website. The website creator has added a Google Recaptcha as a security feature in the form that the user must solve before submitting the form. This is how Google Recaptcha works:
The above diagram describes the whole cycle of form submission and interactions between the user, the web server and Google servers. The light grey interactions are done internally without any user intervention or programming from the developer. The client browser knows only the public key and response code. Even if some stole these data, it would not be possible to use them again. Google ensures that the combination of response code and secret key can only be verified once. In addition, not all response codes can be combined with the secret key, only those that were generated from the website using the public key. If a hacker tried to generate response codes using a Google Recaptcha from its own website, this would not work. Notice that the web server performs its own verification of the captcha. It does not rely on client s verification, because this way it could be tricked.
We will now combine the aforementioned diagrams, in order to realize the Google Recaptcha without keys. There are five different sites involved, the website client-side, which is further divided into the elements that belong to the website domain and the elements that belong to the developer s domain (the iframe), the website server-side, the developer s server-side and the Google servers.
Notice that developer s public captcha key and caller URI are exposed to the iframe, however since iframe is in a different domain than the user, these data cannot be accessed by the client-side and consequently hacked.
The above procedure does not allow anyone to get captcha code from the developer s server, but only those with a ticket. The ticket is requested and obtained between server-sides, so the procedure is secure. Even though the ticket is exposed to the user s browser and can be stolen, its lifetime is very short (some seconds), just as long as it takes for the page to completely load and it can be used only once, so it is practically useless outside the aforementioned procedure.
Also notice that the developer s server gets information about the caller s URI during generation of the ticket, which then exposes to the iframe. This information is valuable, as will be shown below, in order to perform secure communication between the user s page (which resides in the website domain) and the iframe (which resides in the developer s domain).
Communication between Page and Iframe
The user s page and the contained iframe belong to different domains. The browsers for security reasons do not allow cross-domain communication. The user can interact with the captcha that resides in the iframe, however this interaction cannot pass to the parent page. So when captcha is solved and a response code is generated, this code cannot pass to the page, so it cannot be submitted to the server together with the rest form data and so the server cannot verify that the captcha was solved.
In order to make this communication more secure, we use targetOrigin parameter of this method and we set it to the caller s URI when sending messages from the iframe to the parent page and to the developer s URI when going the opposite direction.
What messages do we need to send between the page and the iframe?
- From the iframe to the page
- The response code when captcha gets solved by the user
- Notify the page than captcha expired (it happens if the user solved the captcha but too much time passed until form submission)
- Notify the page that captcha was resized (it happens when additional elements are shown to the user, like photos prompting the user to type a text or select some images matching a pattern)
- From the page to the iframe
- Captcha must be reset (happens after the form has been submitted)
So, if we also include user interaction and captcha solution in the last diagram, then it will become:
A final issue that must be resolved is captcha resizing. Sometimes, the new Google Recaptcha v2 displays additional information, like a gallery of images, prompting the user to select a specific pattern (e.g. select all images showing a beer). This additional visual information overlaps any other content and stays on top until the user makes a selection (or vanishes automatically after some seconds).
However, according to the aforementioned procedure, the captcha exists inside an iframe. Unfortunately iframes cannot resize to fit their contents (not in all cases, but for this definitely) and when the captcha needs to display additional visual information to the user, this information is cut and the user is not able to solve the captcha, so the whole procedure becomes useless.
To resolve this issue, the developer needs to add some extra provisions inside the iframe containing the captcha to detect when captcha resizes and through window messaging to notify the parent window (that owes the iframe) to resize the iframe, so that the whole captcha content is visible.
Monitoring of Google Recaptcha v2 dimensions is not an easy task. The onresize event of DOM HTML elements is not effective, because Google Recaptcha v2 elements are not wrapped into a single container. There are a lot of top-most DIV elements that need to be monitored. However, native onresize event does not work well with DIVs and furthermore these DIVs do not change only their size but also their visibility (which cannot be monitored with onresize event).
To mitigate these problems, first an alternative onresize event is adopted, which works well for DIVs. The script can be found here. In order to monitor changes in visibility, a new HTML5 feature is adopted, Mutation Observers, which monitor changes in elements attributes. When a change is detected, then the size of the top-most DIVs is recalculated and if the combined captcha size has changed, then the parent page is notified using postMessage.
If mutation observers are not supported, then the only way to monitor changes in size effectively is to run a script very often (e.g. every 100ms) that performs recalculation of the size of top-most DIVs, using setTimeout method.
The steps of a procedure for enabling use of the new Google Recaptcha without keys has been demonstrated in detail. The procedure is complex and requires extensive programming from programmers who create plugins including Google Recaptcha, however it is effective, offering high security and unobscured user experience.
This procedure has been implemented in full extend in WordPress File Upload plugin for WordPress. WordPress File Upload is a plugin that WordPress website owners can use to enable file uploads for their customers. It offers many options for selecting and filtering files, it has a very reliable and robust upload algorithm, it can upload files of unlimited size and adopts many security features, including Google Captcha. The plugin offers three options for Google Recaptcha: version 1 , version 2 and version 2 (no account) . The latest, version 2 (no account) is the implementation of the aforementioned procedure and enables website owners to use the plugin and Google Recaptcha v2 without requiring from them to have a Google account and get Google Recaptcha keys.