Challenge --- How Secure Is My CAPTCHA Logic?

See if you can find a hole in the way I create CAPTCHA images that might mean it's not as secure as it should be.

As I mentioned yesterday the image created in the Java Agent is written to the disk. What I didn't mention is that the file is then added to a Rich Text field on a Captcha form and saved as a document with the answer to the captcha in there too. The file is then deleted from the disk and the agent redirects the browser to the file within the document that was just created.

To do this I added an image in PassThru HTML to the form that needs a CAPTCHA, like so:

<img src="/path/to/captchadb.nsf/captcha.jpg?OpenAgent&id=GsiMiuKMOprxdIYXUEe">

The ID is the hash of the DocumentUniqueID assigned to the document at the point of ?OpenForm. There's probably little point to hashing the document's ID but it seemed geekily cool to, so I did.

This ID is stored in an editable field on the CAPTCHA-enabled Form called CaptchaID. The field is type="hidden" so that the value is passed back to the server and the value of the field at ?OpenForm is the same as the value at ?CreateDocument. Otherwise it would change and we'd lose our link between the "session". It's a handy hack of a session, but is it a flaw in the security of the process?

The "captcha.jpg" Agent creates the image and a document in which to store it. It then redirects the browser's request for the CAPTCHA image to a URL such as:

/path/to/captchadb.nsf/0/6BCB41.. ...0470E0F/$file/GsiMiuKMOprxdIYXUEe.jpg

When the document with the CAPTCHA on it is saved the value in the CaptchaID field is used to look in the "captcha database" for the Captcha document with the same key (the one where the image file is stored along with the answer). This answer is tested and the Captcha document is then deleted. If it doesn't match then the user returns to the form and a new image/document is created.

The obvious flaw here is storing both image and answer in the same document to which the Anonymous user has read access and to which a hacker would know the key (but not the UNID). This might seem like a massive hole in security. But is it?

I feel safe in this approach as I have hidden all but one of the database's design elements from the web. The only thing not hidden is the "captcha.jpg" agent. The Form used to store the document and View used for lookups are both hidden. If you traverse back through the image's URL to the following address:

/path/to/captchadb.nsf/0/6BCBF41... ...B00470E0F/

You will get an error 404 saying:

HTTP Web Server: Lotus Notes Exception - Special database object cannot be located

Go back as far as the root of the database:


And you will see "No views found". Guess the name of the view and you'll get another 404.

As far as I can see there's no way whatsoever that an Anonymous web visitor/hacker/bot can get access to the answer which is stored as plain text in the "hidden" document.

As an extra precaution the hidden Form has no actual fields on it when opened in Domino Designer. If the Form wasn't hidden then all they'd see in the browser is a blank page anyway.

How secure is this approach? There's a simple workaround of keeping the file and answer in separate documents and adding Readers field security to the latter, but I don't see the need to, unless you know of one?


    • avatar
    • Kerr
    • Wed 18 Jun 2008 07:07 AM

    I think you've covered all the bases Jake. As long as the user has no way to see the answer you are fine. Ensuring the answer is hidden is just standard Domino security, which you seem to have down pat.

    I take it for this scenario, this is the only "session" you need. If multiple forms need submited, then multiple captchas must be passed?

    Also as a follow up to yesterdays post, I've succesfully added a file to a document via MIME without saving it to disk. I was getting the file as base64 encoded via a webservice, but the principle should be the same.

    • avatar
    • Jake Howlett
    • Wed 18 Jun 2008 07:53 AM

    So there's no internal hidden view they could do a ?ReadViewEntries on or anything like that then?

    I had a go at the MIME yesterday and managed to save an image to a document, but only a document that was committed to the disk before being opened as ?OpenDocument. What I couldn't manage is to add a MIMEEntity to a rich text field on a Form using the WQO agent and having it display to the user. Is that possible?

    • avatar
    • andy
    • Wed 18 Jun 2008 07:55 AM

    OK, this may seem overly simplistic but how about just hashing the file name 123456.jpg which would give you something like... GsiMiuKMOprxdIYXUEe.jpg then when the user types 123456 as the captcha solution you simply hash that value and compare the results to see if they match in the back end.

    The only way for someone to "Solve" it is if they know the alogrithm used to hash it, and if your using domino's own function then it should already be secure. You may not even need to store it as it could be used again.

    Just an idea...

    • avatar
    • Jake Howlett
    • Wed 18 Jun 2008 08:22 AM

    Interesting idea Andy. If I were to start again I'd probably use that technique. As it is I'm not sure it's worth undoing what's there as there's not much to gain in doing so. Unless somebody is yet to point out a massive flaw in the approach I've taken...

    • avatar
    • andy
    • Wed 18 Jun 2008 08:24 AM

    Not sure if this is an issue or not...

    <b>By-passing ACLs set on views</b>

    The fact that you can request a document in one view through another view opens up a security hole. If ACLs are set on a view to give say only admins access, then any documents in that view may be access directly through another view - thus bypassing the access control. This works because the permissions allow access to the database, the fake view and the document in question. At each stage where permission checking takes place the authorization process succeeds. If the request was made through the real view then authorization would fail. Remember by requesting a NoteID you're simply asking for the contents from a position in the database file.

    Extract taken from ...


    • avatar
    • Jake Howlett
    • Wed 18 Jun 2008 08:45 AM

    Thanks for the link Andy. I didn't know that PDF existed and will be reading shortly.

    I know a few of the different ways you can get at documents in database but I'm assuming in my case none of it matters as there's only one Form with which to display any document found and that's not only hidden but also blank.

    I wrote a Java servlet a few years back that highlighted one way {Link} which is now closed (I think/hope).

    • avatar
    • Jake Howlett
    • Wed 18 Jun 2008 08:56 AM

    Having read through the PDF it all seems out of date now. It was written in 2001 and it seems as though everything it describes is no longer applicable?

    • avatar
    • flaz
    • Wed 18 Jun 2008 10:11 AM

    Jake, there's no need to save the file in the disk. For a lot of requests it's extremely inefficient. Look at this: {Link}

    Have a nice day ;)

    • avatar
    • Rob
    • Wed 18 Jun 2008 11:30 AM

    @flaz, I looked at the discussion at your link which discusses converting a PNG image to JPG and saving it to the server hard drive before using it.

    One entry said, "What I do is generate an image in the agent. Then save it to the local file system."

    The other said, "... just get the image stream from Google and save it to a uniquely named file ...".

    So what did I miss? How does this help Jake in not writing the file to the disk first?

  1. There are two issues I want to bring up.

    #1 - Hidden documents aren't secure. You've done well in the hiding of it, but that's not the same. If you want to prevent access, put reader names on it or store it in a db with an ACL. On the submit, have the agent which runs be signed by an ID which DOES have access to look up the answer, but DOES NOT have access to the object with the file itself. There's a lot of details I left out, but from your post you seem up to that. Obscurity is never security.

    #2 - Captcha isn't perfect at all. My favorite captcha hack is when they set up another site which requires captcha input -- a popular one, like maybe a free porn site. When they show users THEIR captcha screen, they use script to do the page load on YOURS to get the captcha image which they then retransmit to the user of their site. The user answers their captcha question, and that answer is then submitted as the answer to your own site. This way, they get real people answering your site's captcha requests without you knowing it.

    That said, you have to be an important target for this to be worthwhile. Opening GMAIL accounts for spam sending, for example, would be a "good" use of this technique. Posting blog comments probably would not.

    • avatar
    • Jake Howlett
    • Wed 18 Jun 2008 03:13 PM

    "Obscurity is never security"


    If a document is that well hidden that there's no *possible* way in the world you can ever see it then I'd say it *is* secure. Is it not? Maybe not secure in the true sense of ACL and Readers fields but surely sometimes you can achieve a certain level of secureness without them?

    I can't use readers fields/ACLs anyway as (is the case with most CAPTCHA-enabled forms) the user is Anonymous.

    • avatar
    • Jake Howlett
    • Thu 19 Jun 2008 03:48 AM

    Thanks to Andy's input I've now made a little more secure by hashing the answer in the "hidden" document and then using VerifyPassword to check the user's input against it.

  2. @Jake -- "A certain level of secureness" isn't the same thing as "secure". The question was, how secure is this implementation. I pointed out that it fails to meet best practices for security documents in Domino and also that there are still ways around this kind of measure even if you make it very very secure in implementation.

    "Secure Enough" is a decision to be made by the business/process owner. This probably meets "Secure Enough" but doesn't meet "Secure" in my opinion.

    • avatar
    • Kerr
    • Thu 19 Jun 2008 11:00 AM

    @Andrew, this isn't security by obscurity. If a domino expert with full knowledge of the system design cannot gain access to the hidden information, then there is no security by obscurity.

    In general with notes client work though, I'd agree. Any user that can access the document can see all values on it, and there is nothing you can do about it other than encrypt the field.

    In a pure web environment though, you can store values on docs that the user should never see, as long as you are careful not to let that information get back to the browser.

    • avatar
    • Jake Howlett
    • Thu 19 Jun 2008 12:13 PM

    I see where you're coming from Andrew but I think we'll have to agree to differ.

    Rather than "Secure Enough" I'd say this was "Completely Secure".

    Dictionary.com says secure means "to guarantee the privacy or secrecy of" which I think this does a pretty good job of. Especially as the answer is hashed now ;o)


  3. I guess my question is from another angle - how quickly are the documents that store the images deleted?

    What is to prevent the user from answering the captcha once manually, and then modifying each requested page for the duration of the lifetime of said document?

    I don't know that that would work, since you've left out some details of the process.

    • avatar
    • Jake Howlett
    • Fri 20 Jun 2008 04:06 AM

    Hi Peter. Are you saying that the user could answer one Captcha -- remembering its CaptchaID -- and then change the code used in each subsequent ?OpenForm to the one they know the answer to? I guess that would be a hole they could hack. In my case the document is deleted each time it's guessed - either rightly or wrongly. The only ones that don't get deleted are the ones where uses request a ?OpenForm and never submit it. They are cleared up by a nightly process when they're more than a day old.

    • avatar
    • Jake Howlett
    • Fri 20 Jun 2008 04:10 AM

    I just went to check what I said above was true and found a huge great hole in my logic. The code said


    If not captcha is nothing then

    'testing logic

    else 'Something wrong. Assume it's ok and continue?

    document.replaceItemValue("CaptchaPassed", "1")

    end if

    Spot the flaw? It's unlikely but if a hacker figured out unfound captcha documents led to a success they all they'd have to do is change the hidden CaptchID field in the form to "foo" and it would pass. Doh!

    I'll change the logic to set a flag for admin approval now.

  4. Jake,

    Deleting after each request (and your other fix) certainly take care of that vector.

Your Comments


About This Page

Written by Jake Howlett on Wed 18 Jun 2008

Share This Page

# ( ) '


The most recent comments added:

Skip to the comments or add your own.

You can subscribe to an individual RSS feed of comments on this entry.

Let's Get Social

About This Website

CodeStore is all about web development. Concentrating on Lotus Domino, ASP.NET, Flex, SharePoint and all things internet.

Your host is Jake Howlett who runs his own web development company called Rockall Design and is always on the lookout for new and interesting work to do.

You can find me on Twitter and on Linked In.

Read more about this site »

More Content