OpenCAPTCHA.org

OpenCAPTCHA.org Specification Rough Draft v0.1.1

Modified: 2009/09/14 00:58 by 24.251.210.126 - Categorized as: Specifications
Edit

OpenCAPTCHA.org Specification

Draft v0.1.1

For feedback or comments, please register as a wiki user and contribute with the Discuss link or e-mail Jon Davis directly at . This version may change unless a Discuss post is made at which point all changes will be queued up for a 0.2 draft. (Please don't let this deter you from posting something!)

URLs:


Edit

Key Components

In an OpenCAPTCHA.org workflow, there are five actors of API interaction:

  1. The Challenge-Answer provider service, which supplies a Challenge/Answer pair to a requesting Challenge or web server. The Challenge-Answer provider service generates, for example, the warped text images that are typically seen in CAPTCHAs today.
  2. The Challenge server, which queries the Challenge-Answer provider service and propagates the challenge to a client. This is an optional "broker" or "proxy" of CAPTCHAs to make it easier to consume a Challenge-Answer provider service securely.
  3. The web server, which can either validate an answer with a Challenge server, or else bypass the Challenge server by invoking the Challenge-Answer provider service directly and passing the challenge to the client inline.
  4. The client, a web site's HTML+Javascript, which either performs a JSONP request to a Challenge server and renders the challenge appropriately, or renders the challenge automatically if the web server bypassed the Challenge server and provided the challenge inline.
  5. The user, the human actor.

Edit

The basic workflow (hands-off proxy scenario):

  1. The HTML+Javascript client invokes a trusted Challenge server's "Get challenge" URL
  2. The Challenge service returns a formatted challenge along with a token.
  3. The client displays the challenge to the user to collect an answer.
  4. The user provides an answer to the client.
  5. The client posts the user's answer along with the Challenge server's token, in addition to whatever other form data is being set up.
  6. The consuming web site's server makes a secondary query to the same Challenge server with the answer and the token, and the Challenge returns JSON {pass: true}, {pass: false}, or {error: '..'} with an error message such as 'Could not find token'.
  7. The Challenge server destroys the token and the answer from memory immediately upon the first query for the correctness of an answer.

Edit

Minimizing Latency

The two-deep proxy hop of the scenario described in the first basic example above creates a potential bottleneck since multiple HTTP requests must be made in order to execute a CAPTCHA challenge/response validation. To minimize latency, the consuming web site can itself consume a Challenge-Answer URL and remove the client-side query to the Challenge server altogether. Doing so requires that the web site works responsibly to forward client request headers for browser support information, as well as flush the Challenge-Answer pair as soon as an answer is validated, whether or not the answer passes validation.

Edit

The alternate basic workflow (hands-on no-proxy scenario):

  1. The consuming web site's server invokes a Challenge-Answer provider service URL.
  2. Challenge-Answer provider service returns a challenge-answer object.
  3. Consuming web site's server retains the answer in memory and puts the challenge in the HTML form for the client to render.
  4. The client renders the challenge.
  5. The user enters the answer to the challenge.
  6. The client sends the form, including the CAPTCHA challenge answer, back to the server.
  7. The consuming web site's server validates that the answer matches the answer already known in memory.
  8. The consuming web site's server destroys all challenge/answer data whether validation passed or not.

Edit

The "Open" part of OpenCAPTCHA.org

In steps #1 and #2 of the first workflow above, there's actually more that goes on here. In fact, the Challenge server acts as a kind of proxy, forwarding the challenge request to one of a list of OpenCAPTCHA.org-compliant Challenge-Answer provider URLs. The provider URL might return a simple image tag, it might return a simple question, it might return a Flash animation. In any case, it always also returns the answer with the challenge; the challenge is strictly intended for client/user consumption, while the answer value is simply a match value that a single query from the consuming web site's server can validate against. Edit

The Basic Spec

Edit

The Challenge Server

The Challenge server that the client invokes is not literally OpenCAPTCHA.org/OpenCAPTCHA.net, but rather a protocol-compliant server that proxies one of a list of Challenge-Answer provider URLs. The server should expose the following interface:

http[s]://{server-host}[:{port}]/{challenge-url}?[type=jsonp][&format=html_input]&callback={callback_function}

.. and the return object returns a JSONP response:

callback_function({
    challenge: '<div class="OpenCAPTCHA-FieldLabel">What is two plus two?</div><div><input type="html_input"
        class="OpenCAPTCHA-Answer" name="OpenCAPTCHA_Answer" />',
    format: 'html_input',
    token:  '#######'
})

The client can then evaluate the format, and in this case (format: 'html_input') put the challenge value directly inside the form, or display it in a "pop-in" (DHTML modal window) dialog.

When a Challenge server is called from a client, the web site's server must still validate the form by querying the Challenge server with an answer validation. The Challenge server should therefore expose the interface:

http[s]://{server-host}[:{port}]/{validate-url}?token={token}&answer={answer}[&type=json]

The response object from the Challenge server should be in the format (assuming JSON type specified in querystring, which should default to JSON anyway):

{
    pass:  {true|false}
  [,error: 'This is the message describing the nature of the error if an error occurred.']
}

Note that the error property can be present but null if no error occurred.

So basically, a valid response might be { pass : true }. Whether the value of "pass" is true or false, the Challenge server MUST destroy any Challenge/Answer pairs or tokenized references it may have in memory, to prevent any pre-validation exploits from accomplishing a full-request-lifecycle attack.

Edit

The Challenge-Answer provider URL

Suggestion: To avoid being scrutinized and heavily tested by malicious users, the Challenge-Answer provider service URL SHOULD be kept secret from end users and be known only by either a web site server or by a Challenge server. Any image URLs that are returned in a challenge value should avoid being similar to the Challenge-Answer provider service URL such that a malicious user can figure out the service URL by making minor tweaks to the URL.

A Challenge-Answer provider URL *MUST* follow the convention:

http[s]://{server-host}[:{port}]/{challenge-answer-url}?[type=json][&format=html_input]

.. where the format field is optional, and return a JSON object similar to the example:

{
    challenge: '<div class="OpenCAPTCHA-FieldLabel">What is two plus two?</div><div><input type="text"
         class="OpenCAPTCHA-Answer" name="OpenCAPTCHA_Answer" />',
    answer: ['4', 'four'],
    caseSensitive: false,
    expires: '2009-11-30T12:00:00',
    format: 'html_input'
}

.. where the answer property is ALWAYS an array of valid answers, even if it has only one answer, and 'expires' is an ISO 8601 date describing when the answer will become invalid or the challenge dependencies (i.e. image assets) will become unavailable. This is primarily useful for images generated by the Challenge-Answer provider that must be flushed at some point; a web server or Challenge server might try to cache a small collection of challenge/answer pairs for performance reasons and must know when these challenge/answer pairs become stale and must be purged.

If a web server or Challenge server does invoke a Challenge-Answer provider service multiple times in order to cache a set of challenge/answer pairs, it MUST always disclose a Referer header in the request pointing to a URL that describes the server making the request, and it should limit its requests to a number that's appropriate for a small buffered cache. There can be no hard limit because different servers have different levels of user traffic, but use discretion. Edit

Format Field in Challenge and Challenge-Answer Query

When invoking either the Challenge server for a Challenge object, or one of the Challenge-Answer provider URLs, the request can include "?format=.." in the querystring of the request. This tells the server to limit the challenge or reformat the challenge to conform to the specified format. If the server cannot produce the challenge in the specified format, or is otherwise unable to produce a challenge for the request, it should return a 501 status code with a formatted (JSON/JSONP/XML, JSON by default) response body:

{ error: 'message goes here ...' }

The request can also specify a list of supported formats by using multiples of "format" or using a comma-delimited list. The Challenge server(s) and the Challenge-Answer provider servers should always assume to .Split(',') the list, but defaulting to be understood as "all formats supported by service" if no format field is specified.

Edit

Formats

The following challenge formats can be used in a Challenge object or in a Challenge-Answer pair object:

  • image - The challenge value is a URL to an image that contains distorted text or a shape that the user can echo as text. This format type may be accompanied with a instruction string value in the containing object that explains to the user what to do with the image (i.e. "How many fingers is this guy holding up?"). This instruction string should be plain-text; any HTML tags should be encoded to be legible text rather than treated as HTML tags.
  • text - The challenge is a plain-text (utf-8) question or instruction. Any HTML tokens such as less-than sign should be encoded to be legible text rather than treated as HTML tags.
  • html - The challenge is an HTML-formatted question or instruction. HTML markup provided should be rendered. Note that the HTML may contain <img> tag(s), and if it does the tag(s) might disclose URLs that are very close to the origin Challenge-Answer provider service URLs.
  • htmlInput - The challenge is an HTML-formatted question or instruction with an input field provided and should be rendered in full. The name of the input field is "OpenCAPTCHA_Answer", and it may be of any HTML type (i.e. hidden, text, etc). This format may also potentially contain Javascript event handlers. Note that the HTML may contain <img> tag(s), and if it does the tag(s) might disclose URLs that are very close to the origin Challenge-Answer provider service URLs.
  • canvasJs - The challenge is executable Javascript, and a single HTML 5 Canvas object is assumed to already be declared as window['OpenCAPTCHA_Canvas'].
  • swf - The challenge is a URL pointing to a .swf file. The .swf file gets played back as a Flash animation to the user. If this format is used, the JSON object MIGHT include the values "width", "height", and "minVersion", where "width" and "height" are suggested width/height dimensions for the plug-in object, and "minVersion" describes the minimum version of Flash that should be installed. Note that Flash and Silverlight require a cross-domain XML file on the server, and that the URL to the .swf might be very close to the origin Challenge-Answer provider service URLs; it might be a good idea to download the file directly and proxy it to the client.
  • xap - The challenge is a URL pointing to a .xap file. The .xap file gets played back as a Silverlight animation to the user. If this format is used, the JSON object MIGHT include the values "width", "height", and "minVersion", where "width" and "height" are suggested width/height dimensions for the plug-in object, and "minVersion" describes the minimum version of Silverlight that should be installed. Note that Flash and Silverlight require a cross-domain XML file on the server, and that the URL to the .xap might be very close to the origin Challenge-Answer provider service URLs; it might be a good idea to download the file directly and proxy it to the client.

The answer format is always plain-text. However, if html_input, canvas_js, swf, or xap challenge formats exploit DOM automation in such a way as to automate the answer field on a form (i.e. ) to generate an answer programmatically, it can be in any standard utf8-encoded format, as long as the correct answer can be matched to the Challenge-Answer pair.

Edit

JSON/JSONP on Challenge and Challenge-Answer Provider Services

When a Challenge service or Challenge-Answer provider service processes a request, the request can be made expecting either a JSON response or a JSONP response. A JSONP response can be explicitly requested by adding "type=jsonp" in the querystring of the request URL. All Challenge services MUST default to the querystring field value of JSONP or else it is not properly implemented, but a Challenge service MUST ALSO support "type=json" to return JSON instead if it was explicitly requested in the querystring, so that a web server can invoke it directly and parse the result as JSON without truncating the response body. Whereas, all Challenge-Answer provider services MUST default to the querystring field value of JSON or else it is not properly implemented, but a Challenge-Answer service MAY also support "type=jsonp" to return JSONP instead if it was requested in the querystring; supporting JSONP would not be useful in production scenarios, but could be useful when exposing the provider with a user-exposed interactive demonstration.

The Challenge services and the Challenge-Answer provider services MAY also support "type=xml" to return an XML flavor of the JSON object.

ScrewTurn Wiki version 2.0.37. Some of the icons created by FamFamFam.