View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0001193 | Main CAcert Website | certificate issuing | public | 2013-07-20 22:28 | 2013-07-23 22:19 |
Reporter | wijnen | Assigned To | |||
Priority | normal | Severity | minor | Reproducibility | always |
Status | new | Resolution | open | ||
Platform | Firefox | OS | Debian GNU/Linux | OS Version | unstable |
Summary | 0001193: patch for allowing domain verification using a HTTP probe instead of e-mail. | ||||
Description | According to (the bottom of) http://wiki.cacert.org/FAQ/NoDomainName, one of the methods to verify a domain is using a HTTP probe, but this is not currently implemented. | ||||
Steps To Reproduce | Log in, go to domains->add, enter a domain, see that it only allows sending e-mails, not checking the content of the web site. | ||||
Additional Information | The attached patch adds an option to the menu where an e-mail address must be selected. This option includes a hash. The user should create a text file containing this hash and place it on the web site as /cacert-probe.txt . When requesting to probe (clicking the button in the menu), the server will wget that file and check that it contains the hash. If it does, then the user has proven to be in control of the domain's web site and should be allowed to issue certificates for it (actually, according to the ruling they need to use an additional validation, but my main goal is to allow verification of domains without the ability to receive e-mail for them, so I hope this extra requirement will only be activated when more options are implemented). Possible problems with the patch: 1. It may not work at all. I didn't see how I could easily set up a system to test it. I'm confident that it doesn't require major changes, however. 2. It's using wget to retrieve the file from the target webserver. This should work, but there might be a better way for doing this in php. Non-issue: Users may have access to some parts of a website, but not all of it. They must only be able to verify the domain if they have access over the top level documents (in particular, /~user/* is not enough). This patch only tries http at (protected) port 80 and only looks for /cacert-probe.txt . A regular user of the system will not be able to place that file on the server, and if no web server is running, will not be able to run a private web server on port 80. | ||||
Tags | No tags attached. | ||||
Attached Files | http-probe.patch (2,540 bytes)
diff --git a/includes/account.php b/includes/account.php index 1a381b8..9c928cb 100644 --- a/includes/account.php +++ b/includes/account.php @@ -543,6 +543,7 @@ $addy[] = $sub; $_SESSION['_config']['addy'] = $addy; $_SESSION['_config']['domain'] = mysql_real_escape_string($newdomain); + $_SESSION['_config']['httphash'] = trim(make_hash()); } if($process != "" && $oldid == 8) @@ -553,6 +554,27 @@ $authaddy = trim(mysql_real_escape_string(stripslashes($_REQUEST['authaddy']))); + if($authaddy == "http hash") + { + // get site/cacert-probe.txt and check if it contains the hash. + $newhash = trim(`/usr/bin/wget -O- http://"$_SESSION['_config']['domain'].'/cacert-probe.txt'"`); + if($newhash != $_SESSION['_config']['httphash']) + { + showheader(_("My CAcert.org Account!")); + echo _("The hash could not be retrieved from http://".$_SESSION['_config']['domain'].'/cacert-probe.txt , or it did not match.'); + showfooter(); + exit; + } + $query = "insert into `domains` set + `domain`='".mysql_real_escape_string($_SESSION['_config']['domain'])."', + `memid`='".$_SESSION['profile']['id']."', + `created`=NOW(), `modified`=NOW(), `hash`=''"; + mysql_query($query); + showheader(_("Updated"), _("Updated")); + echo _("Your domain has been verified. You can now start issuing certificates for this domain.<br>You can remove cacert-probe.txt from your website."); + exit; + } + if($authaddy == "" || !is_array($_SESSION['_config']['addy'])) { showheader(_("My CAcert.org Account!")); diff --git a/pages/account/8.php b/pages/account/8.php index 79448d1..f25ba7f 100644 --- a/pages/account/8.php +++ b/pages/account/8.php @@ -19,7 +19,14 @@ <table align="center" valign="middle" border="0" cellspacing="0" cellpadding="0" class="wrapper"> <tr> - <td colspan="2" class="title"><?=_("Please choose an authority email address")?></td> + <td colspan="2" class="title"><?=sprintf(_("HTTP: please create a file named %s in the root of your web server containing only this key"), "cacert-probe.txt")?></td> + </tr> + <tr> + <td class="DataTD" width="75"><input type="radio" name="authaddy" value="http hash"<? if($tagged == 0) { echo " checked=\"checked\""; $tagged = 1; } ?> /></td> + <td class="DataTD" width="175"><?=$_SESSION['_config']['httphash']?></td> + </tr> + <tr> + <td colspan="2" class="title"><?=_("E-mail: please choose an authority email address")?></td> </tr> <? $tagged=0; if(is_array($_SESSION['_config']['addy'])) http-probe-2.patch (2,613 bytes)
diff --git a/includes/account.php b/includes/account.php index 1a381b8..1659c0d 100644 --- a/includes/account.php +++ b/includes/account.php @@ -543,6 +543,7 @@ $addy[] = $sub; $_SESSION['_config']['addy'] = $addy; $_SESSION['_config']['domain'] = mysql_real_escape_string($newdomain); + $_SESSION['_config']['httphash'] = make_hash(); } if($process != "" && $oldid == 8) @@ -553,6 +554,27 @@ $authaddy = trim(mysql_real_escape_string(stripslashes($_REQUEST['authaddy']))); + if($authaddy == "http hash") + { + // get site/cacert-probe.txt and check if it contains the hash. + $newhash = file_get_contents('http://'.$_SESSION['_config']['domain'].'/cacert-probe.txt', NULL, NULL, NULL, strlen($_SESSION['_config']['httphash'])); + if(strlen($newhash) == 0 || $newhash != $_SESSION['_config']['httphash']) + { + showheader(_("My CAcert.org Account!")); + echo _("The hash could not be retrieved from http://".$_SESSION['_config']['domain'].'/cacert-probe.txt , or it did not match.'); + showfooter(); + exit; + } + $query = "insert into `domains` set + `domain`='".mysql_real_escape_string($_SESSION['_config']['domain'])."', + `memid`='".$_SESSION['profile']['id']."', + `created`=NOW(), `modified`=NOW(), `hash`=''"; + mysql_query($query); + showheader(_("Updated"), _("Updated")); + echo _("Your domain has been verified. You can now start issuing certificates for this domain.<br>You can remove cacert-probe.txt from your website."); + exit; + } + if($authaddy == "" || !is_array($_SESSION['_config']['addy'])) { showheader(_("My CAcert.org Account!")); diff --git a/pages/account/8.php b/pages/account/8.php index 79448d1..f25ba7f 100644 --- a/pages/account/8.php +++ b/pages/account/8.php @@ -19,7 +19,14 @@ <table align="center" valign="middle" border="0" cellspacing="0" cellpadding="0" class="wrapper"> <tr> - <td colspan="2" class="title"><?=_("Please choose an authority email address")?></td> + <td colspan="2" class="title"><?=sprintf(_("HTTP: please create a file named %s in the root of your web server containing only this key"), "cacert-probe.txt")?></td> + </tr> + <tr> + <td class="DataTD" width="75"><input type="radio" name="authaddy" value="http hash"<? if($tagged == 0) { echo " checked=\"checked\""; $tagged = 1; } ?> /></td> + <td class="DataTD" width="175"><?=$_SESSION['_config']['httphash']?></td> + </tr> + <tr> + <td colspan="2" class="title"><?=_("E-mail: please choose an authority email address")?></td> </tr> <? $tagged=0; if(is_array($_SESSION['_config']['addy'])) | ||||
Reviewed by | |||||
Test Instructions | |||||
|
I've uploaded a new version, which fixes two problems: 1. There was no check for an empty result. Since the hash couldn't be empty, this was no security issue, but now I'm checking it just to be sure. 2. wget doesn't limit the download size, so a DoS attack was possible by placing a giant file named /cacert-probe.txt at the server and probing it. Now I've used file_get_contents (which is better than using an external program anyway) and used its maxsize argument. |
|
per CPS 4.2.2 this is an allowed variant https://www.cacert.org/policy/CertificationPracticeStatement.php#p4.2 section Domain verification |
|
To avoid the situation where an "attacker" could search for all domains registered with CAcert by looking up a fixed filename. Furthermore the filename should be based on details specific to the user account it is registered with, forcing revalidations of the domain after transfer to another account to fail. Additionally we should allow administrators to authenticate requests from the CAcert servers by some domain or user specific token. The used data might look like: - $content = makehash(); - $filename = "cacert.".md5(salt.md5(uid).salt.makehash().salt.md5(domid)).".txt"; - $token = md5(salt.md5(uid).salt.md5(domid)); - $uri = http://$domain/$filename?auth=$token This uses the auth parameter as a shared secret between CAcert and the webserver without neeing the server to act on the value of the auth parameter, thus making its interpretation optional. Also the patch should check for the following things: 1. RFC-reserved IP address ranges should be declined 2. domains resolving into any of the CAcert internal networks should be declined and filtered by firewall 3. The method a domain was verified should be displayed |
Date Modified | Username | Field | Change |
---|---|---|---|
2013-07-20 22:28 | wijnen | New Issue | |
2013-07-20 22:28 | wijnen | File Added: http-probe.patch | |
2013-07-21 14:46 | wijnen | File Added: http-probe-2.patch | |
2013-07-21 14:49 | wijnen | Note Added: 0004173 | |
2013-07-23 20:52 | Uli60 | Note Added: 0004182 | |
2013-07-23 22:19 | BenBE | Note Added: 0004186 | |
2013-07-23 22:20 | BenBE | Note Edited: 0004186 |