如何在在线表单中验证captcha



我的工作是为比赛创建一个表格并收集数据。这些数据将由一家我们用来发送电子邮件的公司收集(比如Mail chimp)。该公司(通过其在线软件"战役指挥官"发送电子邮件)生成了以下表格。正如您所看到的,它并不能验证captcha。我需要什么代码才能在不离开表单的情况下验证captcha?该网站是用PHP开发的。谢谢你的帮助。上帝保佑我们。Julian P.

<html>
<head>
<title>Webform</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<script language="javascript">
function isInteger(input,fieldName){
var i;
for(i=0;i<input.value.length;i++){
var c=input.value.charAt(i);
if(((c<'0')||(c>'9'))){
alert('The number in '+fieldName+' is not valid.');
input.focus();
return false;
}}
return true;
}
var dtCh='/';
var minYear=1900;
var maxYear=2100;
function isValidInteger(s){
var i;
for(i=0;i<s.length;i++){
var c=s.charAt(i);
if(((c<'0')||(c>'9'))) return false;
}
return true;
}
function stripCharsInBag(s,bag){
var i;
var returnString='';
for(i=0;i<s.length;i++){
var c=s.charAt(i);
if(bag.indexOf(c)==-1) returnString+=c;
}
return returnString;
}
function daysInFebruary(year){
return(((year%4==0)&&((!(year % 100 == 0))||(year%400==0)))?29:28);
}
function DaysArray(n){
for(var i=1;i<=n;i++){
this[i]=31;
if(i==4||i==6||i==9||i==11){this[i]=30;}
if(i==2){this[i]=29;}
}
return this;
}
function isDateOK(dtStr){
if(dtStr=='') return true;
var daysInMonth=DaysArray(12);
var pos1=dtStr.indexOf(dtCh);
var pos2=dtStr.indexOf(dtCh,pos1+1);
var strDay=dtStr.substring(0,pos1);
var strMonth=dtStr.substring(pos1+1,pos2);
var strYear=dtStr.substring(pos2+1);
strYr=strYear;
if(strDay.charAt(0)=='0'&&strDay.length>1) strDay=strDay.substring(1);
if(strMonth.charAt(0)=='0'&&strMonth.length>1) strMonth=strMonth.substring(1);
for(var i=1;i<=3;i++){
if(strYr.charAt(0)=='0'&&strYr.length>1) strYr=strYr.substring(1);
}
month=parseInt(strMonth);
day=parseInt(strDay);
year=parseInt(strYr);
if(pos1==-1||pos2==-1){
alert('The date format should be : dd/mm/yyyy.');
return false;
}
if(strMonth.length<1||month<1||month>12){
alert('Please enter a valid month.');
return false;
}
if(strDay.length<1||day<1||day>31||(month==2&&day>daysInFebruary(year))||day>daysInMonth[month]){
alert('Please enter a valid day.');
return false;
}
if(strYear.length!=4||year==0||year<minYear||year>maxYear){
alert('Please enter a valid 4 digit year between '+minYear+' and '+maxYear+'.');
return false;
}
if(dtStr.indexOf(dtCh,pos2+1)!=-1||isValidInteger(stripCharsInBag(dtStr,dtCh))==false){
alert('Please enter a valid date.');
return false;
}
return true;
}
function modifyDateFormat(dt){
var valuesTable=dt.value.split(dtCh);
dt.value=valuesTable[1]+dtCh+valuesTable[0]+dtCh+valuesTable[2];
}
function isEmail(emailAddress){
emailAddressValue=emailAddress.value.toLowerCase();
var countryTLDs=/^(ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cat|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cu|cv|cx|cy|cz|de|dj|dk|dm|do|dz|ec|ee|eg|eh|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|st|sv|sy|sz|tc|td|tf|tg|th|tj|tk|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|um|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw)$/;
var gTLDs=/^(aero|asia|biz|cat|com|coop|edu|geo|gov|info|int|jobs|mil|mobi|museum|name|net|org|post|pro|tel|travel)$/;
var basicAddress=/^(.+)@(.+)$/;
var specialChars='\(\)><@,;:\\\"\.\[\]';
var validChars='[^\s'+specialChars+']';
var validCharset='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzöå0123456789'-_.+';
var quotedUser='("[^"]*")';
var atom=validChars+'+';
var word='('+atom+'|'+quotedUser+')';
var validUser=new RegExp('^'+word+'(.'+word+')*$');
var symDomain=new RegExp('^'+atom+'(.'+atom+')*$');
var matchArray=emailAddressValue.match(basicAddress);
if(emailAddress.value==''||emailAddress==null){
return true;
}
if(matchArray==null){
alert('The Email address doesn't seem to be correct,nplease check syntax.');
emailAddress.focus();
return false;
}else{
var user=matchArray[1];
var domain=matchArray[2];
for(i=0;i<user.length;i++){
if(validCharset.indexOf(user.charAt(i))==-1){
alert('The Email address contains invalid characters,nplease check the username.');
emailAddress.focus();
return false;
}
}
for(i=0;i<domain.length;i++){
if(validCharset.indexOf(domain.charAt(i))==-1){
alert('The Email address contains invalid characters,nplease check the domain.');
emailAddress.focus();
return false;
}
}
if(user.match(validUser)==null){
alert('The Email address doesn't seem to be correct,nplease check the username.');
emailAddress.focus();
return false;
}
var atomPat=new RegExp('^'+atom+'$');
var domArr=domain.split('.');
var len=domArr.length;
for(i=0;i<len;i++){
if(domArr[i].search(atomPat)==-1){
alert('The Email address doesn't seem to be correct,nplease check the domain name.');
emailAddress.focus();
return false;
}
}
if((domArr[domArr.length-1].length==2)&&(domArr[domArr.length-1].search(countryTLDs)==-1)){
alert('The Email address doesn't seem to be correct,nplease check domain suffix.');
emailAddress.focus();
return false;
}
if((domArr[domArr.length-1].length>2)&&(domArr[domArr.length-1].search(gTLDs)==-1)){
alert('The Email address doesn't seem to be correct,nplease check domain suffix.');
emailAddress.focus();
return false;
}
if((domArr[domArr.length-1].length<2)||(domArr[domArr.length-1].length>6)){
alert('The Email address doesn't seem to be correct,nplease check domain suffix.');
emailAddress.focus();
return false;
}
if(len<2){
alert('The Email address doesn't seem to be correct,nplease check missing hostname.');
emailAddress.focus();
return false;
}
}
return true;
}
function mandatoryCheckBox(checkBox,fieldName){
var nbcheck=0;
if(checkBox.length==undefined){
if(checkBox.checked){ nbcheck++; }
}else{
for (counter=0;counter<checkBox.length;counter++){
if(checkBox[counter].checked){ nbcheck++; }
}
}
if(nbcheck==0){
alert('Please select your '+fieldName+'.');
return false;
}
return true;
}
function mandatoryDropDown(dropDown,fieldName){
if(dropDown.options[dropDown.options.selectedIndex].value == ""){
alert('Please select your '+fieldName+'.');
dropDown.focus();
return false;
}
return true;
}
String.prototype.trim = function() { return this.replace(/^s*(b.*b|)s*$/, "$1");    }
function mandatoryText(input,fieldName){
if(input.value.trim()==''||input==null){
alert('Please enter your '+fieldName+'.');
input.focus();
return false;
} else {
return true;
}
}
function validForm(){
if(!mandatoryText(document.getElementById('FIRSTNAME_FIELD'), 'First name')) return;
if(!mandatoryText(document.getElementById('LASTNAME_FIELD'), 'Surname')) return;
if(!mandatoryText(document.getElementById('DATEOFBIRTH_FIELD'), 'Date of birth')) return;
if(!isDateOK(document.getElementById('DATEOFBIRTH_FIELD').value)) return;
if(!mandatoryText(document.getElementById('EMAIL_FIELD'), 'Email')) return;
if(!isEmail(document.getElementById('EMAIL_FIELD'))) return;
if(!mandatoryText(document.getElementById('EMVCELLPHONE_FIELD'), 'Mobile')) return;
if(!isInteger(document.getElementById('EMVCELLPHONE_FIELD'), 'Mobile')) return;
if(!mandatoryDropDown(document.getElementById('STORE_NAME_FIELD'), 'Nearest shop')) return;
if(!mandatoryCheckBox(document.getElementById('emvForm').OPTIN_FIELD, 'Opt in to marketing emails')) return;
if(document.getElementById('DATEOFBIRTH_FIELD').value!='') modifyDateFormat(document.getElementById('DATEOFBIRTH_FIELD'));
document.getElementById('emvForm').submit();
if(document.getElementById('DATEOFBIRTH_FIELD').value!='') modifyDateFormat(document.getElementById('DATEOFBIRTH_FIELD'));
}
</script>
</head>
<body>
<form name="emvForm" id="emvForm" action="http://tre.emv3.com/D2UTF8" method="POST" target="_top">
<input type="hidden" name="emv_tag" value="876020001C384269" />
<input type="hidden" name="emv_ref" value="EdX7CqkdLe_d8SA9MOPQNCffL0p6Hq3D-jmueKEyWsbQKbo" />
<table>
<tr>
<td>
First name
</td>
<td>
<input type="text" id="FIRSTNAME_FIELD" name="FIRSTNAME_FIELD" value="" size="30" maxlength="64">
</td>
</tr>
<tr>
<td>
Surname
</td>
<td>
<input type="text" id="LASTNAME_FIELD" name="LASTNAME_FIELD" value="" size="30" maxlength="64">
</td>
</tr>
<tr>
<td>
Date of birth
</td>
<td>
<input type="text" id="DATEOFBIRTH_FIELD" name="DATEOFBIRTH_FIELD" value="" size="30" maxlength="64">
</td>
</tr>
<tr>
<td>
Email
</td>
<td>
<input type="text" id="EMAIL_FIELD" name="EMAIL_FIELD" value="" size="30" maxlength="64">
</td>
</tr>
<tr>
<td>
Mobile
</td>
<td>
<input type="text" id="EMVCELLPHONE_FIELD" name="EMVCELLPHONE_FIELD" value="" size="30" maxlength="64">
</td>
</tr>
<tr>
<td>
Nearest shop
</td>
<td>
<select id="STORE_NAME_FIELD" name="STORE_NAME_FIELD">
<option selected value=""></option>
<option value="Aberdeen ">Aberdeen </option>
<option value="Acton ">Acton </option>
<option value="Aldgate ">Aldgate </option>
<option value="Ashford ">Ashford </option>
<option value="Aylesbury ">Aylesbury </option>
<option value="Baker Street ">Baker Street </option>
<option value="Balham ">Balham </option>
<option value="Ballymena ">Ballymena </option>
<option value="Barnet ">Barnet </option>
<option value="Beckenham ">Beckenham </option>
<option value="Belfast ">Belfast </option>
<option value="Bethnal Green ">Bethnal Green </option>
<option value="Bexleyheath ">Bexleyheath </option>
<option value="Biggleswade ">Biggleswade </option>
<option value="Birmingham ">Birmingham </option>
<option value="Birmingham New Street ">Birmingham New Street </option>
<option value="Bishopsgate ">Bishopsgate </option>
<option value="Bond Street ">Bond Street </option>
<option value="Bromley ">Bromley </option>
<option value="Camberwell ">Camberwell </option>
<option value="Cambridge ">Cambridge </option>
<option value="Camden Town ">Camden Town </option>
<option value="Chelmsford ">Chelmsford </option>
<option value="Chelsea ">Chelsea </option>
<option value="Cheltenham ">Cheltenham </option>
<option value="Chester ">Chester </option>
<option value="Chiswick ">Chiswick </option>
<option value="Clacton-on-Sea ">Clacton-on-Sea </option>
<option value="Clapham High Street ">Clapham High Street </option>
<option value="Clapham Junction ">Clapham Junction </option>
<option value="Colchester ">Colchester </option>
<option value="Coleraine ">Coleraine </option>
<option value="Covent Garden ">Covent Garden </option>
<option value="Coventry ">Coventry </option>
<option value="Cricklewood ">Cricklewood </option>
<option value="Crouch End ">Crouch End </option>
<option value="Croydon ">Croydon </option>
<option value="Dalston ">Dalston </option>
<option value="Ealing ">Ealing </option>
<option value="Earls Court ">Earls Court </option>
<option value="Edgware ">Edgware </option>
<option value="Exeter ">Exeter </option>
<option value="Farringdon ">Farringdon </option>
<option value="Fleet Street ">Fleet Street </option>
<option value="Fulham ">Fulham </option>
<option value="Glasgow ">Glasgow </option>
<option value="Godalming ">Godalming </option>
<option value="Golders Green ">Golders Green </option>
<option value="Guildford ">Guildford </option>
<option value="Hackney ">Hackney </option>
<option value="Hammersmith ">Hammersmith </option>
<option value="Hampstead ">Hampstead </option>
<option value="Highbury ">Highbury </option>
<option value="Holborn ">Holborn </option>
<option value="Ipswich ">Ipswich </option>
<option value="Angel ">Angel </option>
<option value="Kensington ">Kensington </option>
<option value="Kentish Town ">Kentish Town </option>
<option value="Kilburn ">Kilburn </option>
<option value="Kings Lynn ">Kings Lynn </option>
<option value="Kingston ">Kingston </option>
<option value="Knightsbridge ">Knightsbridge </option>
<option value="Leadenhall Market ">Leadenhall Market </option>
<option value="Lewisham ">Lewisham </option>
<option value="Lisburn ">Lisburn </option>
<option value="Lincoln ">Lincoln </option>
<option value="Londonderry ">Londonderry </option>
<option value="Luton ">Luton </option>
<option value="Maidenhead ">Maidenhead </option>
<option value="Maidstone ">Maidstone </option>
<option value="Mansion House ">Mansion House </option>
<option value="Marble Arch ">Marble Arch </option>
<option value="Marlow ">Marlow </option>
<option value="Marylebone ">Marylebone </option>
<option value="Mayfair ">Mayfair </option>
<option value="Milton Keynes ">Milton Keynes </option>
<option value="Muswell Hill ">Muswell Hill </option>
<option value="Newbury ">Newbury </option>
<option value="Northampton ">Northampton </option>
<option value="Norwich ">Norwich </option>
<option value="Notting Hill Gate ">Notting Hill Gate </option>
<option value="Oxford ">Oxford </option>
<option value="Peckham ">Peckham </option>
<option value="Peterborough ">Peterborough </option>
<option value="Pimlico ">Pimlico </option>
<option value="Portobello ">Portobello </option>
<option value="Putney ">Putney </option>
<option value="Queensway ">Queensway </option>
<option value="Reading ">Reading </option>
<option value="Richmond ">Richmond </option>
<option value="Romford ">Romford </option>
<option value="Shepherds Bush ">Shepherds Bush </option>
<option value="Slough ">Slough </option>
<option value="Soho ">Soho </option>
<option value="South Kensington ">South Kensington </option>
<option value="Southend ">Southend </option>
<option value="St Johns Wood ">St Johns Wood </option>
<option value="Staines ">Staines </option>
<option value="Streatham ">Streatham </option>
<option value="Surbiton ">Surbiton </option>
<option value="Sutton ">Sutton </option>
<option value="Swiss Cottage ">Swiss Cottage </option>
<option value="Sydenham ">Sydenham </option>
<option value="Tooting ">Tooting </option>
<option value="Tottenham Court Road ">Tottenham Court Road </option>
<option value="Tunbridge Wells ">Tunbridge Wells </option>
<option value="Twickenham ">Twickenham </option>
<option value="Uxbridge ">Uxbridge </option>
<option value="Victoria ">Victoria </option>
<option value="Walthamstow ">Walthamstow </option>
<option value="Walworth Road ">Walworth Road </option>
<option value="Wandsworth ">Wandsworth </option>
<option value="Watford ">Watford </option>
<option value="Welwyn Garden City ">Welwyn Garden City </option>
<option value="Westminster ">Westminster </option>
<option value="Wimbledon ">Wimbledon </option>
<option value="Windsor ">Windsor </option>
<option value="Wokingham ">Wokingham </option>
<option value="Wood Green ">Wood Green </option>
<option value="Woolwich ">Woolwich </option>
</select>
</td>
</tr>
<tr>
<td>
</td>
<td>
<input type="hidden" id="STORE_EMAIL_FIELD" name="STORE_EMAIL_FIELD" value="">
</td>
</tr>
<tr>
<td>
</td>
<td>
<input type="hidden" id="WEB_HOME_FIELD" name="WEB_HOME_FIELD" value="">
</td>
</tr>
<tr>
<td>
</td>
<td>
<input type="hidden" id="SOURCE_FIELD" name="SOURCE_FIELD" value="St Petes">
</td>
</tr>
<tr>
<td>
Opt in to marketing emails
</td>
<td>
<input type="checkbox" id="OPTIN_FIELD" name="OPTIN_FIELD" value="true">
</td>
</tr>

<tr>
<td style="border:1px solid red">
<img id="captcha" src="/maininc/securimage/securimage_show.php" alt="CAPTCHA Image" />
</td>
<td>
<input type="text" name="captcha_code" size="10" maxlength="6" />
<a href="#" onclick="document.getElementById('captcha').src = '/maininc/securimage/securimage_show.php?' + Math.random(); return false">[ Different Image ]</a>
</td>
</tr>

<tr>
<td colspan="2" align="center">
<input type="button" value="Submit Form" onClick="javascript:validForm();">
</td>
</tr>
</table>
</form>
</body>
</html>

验证captcha没有在客户端完成,原因有几个:

  1. 客户端可以禁用JS
  2. 你发送给客户端的任何代码都可以被用户看到,所以机器人很快就会获取captcha内容并向你的网站发送垃圾邮件
  3. 仅JS验证是远远不够的

如果你粘贴的代码实际上是公司"销售"的,那就寻找另一个供应商(老实说,这是糟糕的代码)
在不提交表单的情况下验证captcha的唯一方法是发送AJAX请求,但要小心!这意味着机器人可以随意尝试随机字符串,每次发送请求并获得即时反馈,而无需发送除captcha之外的任何其他数据。

是的,captcha很烦人,很麻烦,是的,它们破坏了用户体验,是的它们会激怒我们所有人,但它们是一种必要的邪恶。只需保持captcha的原样,将其与表格一起发送,并希望您的用户能够弄清楚。

"在不离开表单的情况下验证CAPTCHA"是什么意思?无论如何,您必须提交表单才能将数据发送到服务器,所以只需验证即可。你可以添加一些预验证的孩子,以确保提供正确的答案,但任何确定的垃圾邮件发送者都可以删除你的客户端验证。您必须进行服务器端验证才能获得CAPTCHA提供的任何好处。

你有CAPTCHA图像制作工作吗?CAPTCHA背后的大问题是,必须生成人类可读但计算机OCR难以读取的单词或数字图像,然后才能验证用户提供的输入是否与这些图像匹配。如果你是新手,这不是你自己能做的事情。

如果您还没有生成验证码图像,请在线搜索验证码服务提供商。甚至还有一些免费的,比如captchas.net(尽管我不能保证它们的质量或可靠性)。

此外,我想补充一点,你可以采取一些措施来减少或消除不涉及CAPTCHA的垃圾邮件:

  • 确保表单显示了一个隐藏字段,该字段包含特定于当前会话的值。自动垃圾邮件发送者将不得不刮你的表格
  • 设置一个短时间间隔的cookie,看看它是否不见了。如果不是,那么它就不是真正的浏览器中的真正用户
  • 为一个子域设置cookie,然后查看是否可以从同一顶级域的另一个子域访问它。如果可以的话,那么它就不是一个真正的浏览用户
  • 让javascript执行一些相当复杂的计算(您已经知道正确的答案),并让它在隐藏的表单字段中提交答案。如果你改变计算和运行的代码,可能很难有人对你的网站进行自动化
  • 速率限制到您的站点的连接尝试。特别是,如果有人要求填写至少需要一分钟的表格,不要在一分钟内接受帖子
  • 事实上,对于之前的所有想法,与其阻止垃圾邮件发送者,不如接受他们的帖子,但如果它被归类为非真实浏览器或垃圾邮件,则将其显示给原始IP地址/用户。他可能没有意识到这篇帖子没有向其他人展示,这种缺乏反馈的情况会阻碍他向你的网站发送垃圾邮件
  • 提供五个提交按钮,但使用CSS隐藏除一个按钮外的所有按钮。确保你点击了正确的一个,并使它在每次请求表单时都有不同的代码。垃圾邮件发送者必须解析CSS规则,以找出显示的规则
  • 慢慢旋转表单目标、表单名称、表单元素名称和网站的一些基本html结构(以一种不会改变最终结果的方式)。如果你旋转得太快,垃圾邮件发送者会弄清楚你在做什么。如果你每隔几天轮换一次,垃圾邮件发送者就会成功地为你的网站编写脚本(假设他克服了其他障碍),然后继续前进。但随后你改变了一切,他的脚本就坏了
  • 呈现一个表单,然后每分钟使用一次ajax来获得一个新的隐藏表单值。不要只返回一个值,而是返回用于更新表单的javascript。有进取心的自动垃圾邮件发送者将被迫解析JSON或javascript,以找出如何让表单在正确的时间提交正确的值。当然,在服务器端,您希望表单在提交时具有正确的值
  • 使用javascript记录接收焦点的控件。让用户点击他想要提交的每个表单字段,以获得成功。浏览器保存了不完整的表单数据的用户可能会感到不便,但正常使用网站并只在表单中输入数据然后提交的用户将不会感到不便
  • 查找将被非浏览器脚本遗漏的有效请求标头。当请求头没有意义时,应用更高标准的表单验证(如captcha)
  • 使用重定向来确保垃圾邮件发送者必须支持它们
  • 总之,做任何可以提高标准的事情,这样试图垃圾邮件的自定义代码就会遇到问题。你可能需要采取特殊的步骤来为你的真实用户保留可用性,但我相信这是可以做到的

p.S.您的问题中的电子邮件地址验证不好。它将阻止使用许多完全有效的字符。例如,地址的名称部分应该允许的不仅仅是字母和数字。特别是,+是一个有效的字符,许多人都使用它。不要对你的用户那样做。

最新更新