reCaptcha v3 with ColdFusion - coldfusion

I'm trying to integrate reCaptcha (v3) to a ColdFusion site. I'm not too hot on the CF syntax and currently I'm seemingly getting nothing back from the verify request on the server side.
Can anyone see anything obviously wrong and/or point me in the right direction please?
Client Side:
<script src='https://www.google.com/recaptcha/api.js?render=6..."></script>
<script>
grecaptcha.ready(function() {
grecaptcha.execute('6...', {action: 'contact'})
.then(function(token) {
$("#recaptchaToken").val(token);
});
});
</script>
I've got a hidden field recaptchaToken in my form and I can see the token value going in to it.
Server Side:
<cfhttp
url="https://www.google.com/recaptcha/api/siteverify"
method="POST"
result="captchaResponse">
<cfhttpparam
type="formfield"
name="secret"
value='6...'
/>
<cfhttpparam
type="formfield"
name="response"
value='#form.recaptchaToken#'
/>
</cfhttp>
<cfdump var=#captchaResponse.filecontent# />
I'm getting a red box output titled object of java.io.ByteArrayOutputStream
I've tried to dump both captchaResponse and captchaResponse.filecontent to no avail.
I'm expecting data in the form of:
{
"success": true|false, // whether this request was a valid reCAPTCHA token for your site
"score": number // the score for this request (0.0 - 1.0)
"action": string // the action name for this request (important to verify)
"challenge_ts": timestamp, // timestamp of the challenge load (ISO format yyyy-MM-dd'T'HH:mm:ssZZ)
"hostname": string, // the hostname of the site where the reCAPTCHA was solved
"error-codes": [...] // optional
}
Update
The solution seems to be as Alex suggested below:
<cfdump var=#toString(captchaResponse.filecontent)# />
This gives me a JSON string in the format expected so I can convert this to an object and complete the verification.

Whenever cfhttp is not sure how to treat a response, the raw content stays untouched and is kept as Byte array. This usually indicates that the Content-Type header is not specified by the responding server or the content was only partially retrieved.
To force a string representation of the content, you can use toString() to convert the raw Byte array, e.g. toString(captchaResponse.filecontent). The function is quite robust and can also handle already converted strings, so it is usually safe to use.
However, there is something else to be aware of here. When using cfhttp without setting the throwOnError attribute to true (the default value is false), failed HTTP requests will still return a result, a crippled result. The struct will not contain the fileContent key and thus cause an exception at runtime. You might want to add error handling here, in case https://www.google.com/recaptcha/api/siteverify is not reachable or the accepted TLS protocol is not supported by your JRE. We had this issue with SNI and TLS 1.2 with a former version of ColdFusion, namely 8. Be warned.

Related

Cfhttp and mailgun api

I’ve been trying to configure Mailgun API with Coldfusion's Cfhttp and can’t figure out the format to pass the variables. I configured it in about 5 minutes with Python, and have to roll it to a Coldfusion front end. I’ve used the same basic structure as I did in Python, and it all works great in Python.
I’ve been able to make a connection, but I have not been able to send mail. I know it has to do with the structure, and I can’t find a working example anywhere.
How do you build the cfhttp to pass the required data? Is the data=data I would use in the request in Python the same as a cfhttpparam in ColdFusion? And is it a header, or a body?
My Coldfusion code is below, i've replaced secret information with domain.com
<cfscript>
mailgun_variables = '{
"company_id": 1008,
"company_contact": "Joe Smith",
"random_key": "91A303C8-91FB-AA1D-DE07F18782594721"
}';
data= '{
"from": "email#domain.com",
"to": "email#domain.com",
"subject": "Subject line",
"template": "welcome",
"o:tag": ["welcome", "welcome-countdown", "welcome-alt", "coldfusion"],
"h:X-Mailgun-Variables": #mailgun_variables#}';
</cfscript>
<cfhttp url="https://api.mailgun.net/v3/domain.com/messages"
method="POST"
username="api"
password="APIKEY"
result="response" >
<cfhttpparam type="header" name="Content-Type" value="application/json" />
<cfhttpparam type="header" name="data" value="#serializeJSON(data)#">
</cfhttp>
My error message is a 400 Bad request, {"message":"from parameter is missing"}.
Any guidance or links to examples would be much appreciated. Or maybe you can obviously spot what I am doing wrong?
I ended up having to do a lot of trial and error, but have working code if anyone else ever runs into this issue. Mailgun support was no help.
The answer ended up being that everything had to be passed as cfhttpparam formfields. I also ran into a lot of challenges with tagging and using template variables, but got it all worked out.
I added it to Github for anyone to use, and will continue to improve it there as I get more in-depth with it.
https://github.com/convurt/Mailgun-Coldfusion-Sendmail
cfhttp(method="POST", url="https://api.mailgun.net/v3/DOMAIN.COM/messages", result="response", username="api", password="MAILGUN API KEY") {
cfhttpparam(name="from", type="formfield", value="#email_from#");
cfhttpparam(name="h:Reply-To", type="formfield", value="#reply_to#");
cfhttpparam(name="to", type="formfield", value="#email_to#");
cfhttpparam(name="subject", type="formfield", value="#email_subject#");
// loop over tag list, I could not get it to work correctly as a list
for (t in tags) {
cfhttpparam(name="o:tag", type="formfield", value="#t#");
}
cfhttpparam(name="template", type="formfield", value="#template#");
// custom paramamter for template
cfhttpparam(name="t:variables", type="formfield", value="#t_variables#");

Difference between header and cookie for cfhttpparam type

I am working on a ColdFusion app that authenticates to SharePoint Online and pulls some files using SharePoint's REST API as described in http://paulryan.com.au/2014/spo-remote-authentication-rest/
When I try to obtain the FormDigestValue by posting to _api/contextinfo if I set the cfhttpparam type to cookie I get a 403 forbidden, but if I pass the cookies as a header everything works but I don't understand why.
<cfhttpparam
type="header"
name="cookie"
value="rtFa=#rtFa#;FedAuth=#FedAuth#"
/>
Works but
<cfhttpparam
type="cookie"
name="rtFa"
value="#rtFa#"
/>
<cfhttpparam
type="cookie"
name="FedAuth"
value="#FedAuth#"
/>
Fails
The best way to see what is happening would be to inspect the traffic and see what is happening. Other than that, I know that the difference between using the header type and the cookie type for the cfhttpparam tag is URL encoding.
When you use the header type the value is not URL encoded.
When you use the cookie type the value is URL encoded.
So my guess would be that their API does not like when the value is URL encoded.
Document reference for cfhttpparam attributes.

connecting to smarter stats through cfhttp

I am trying to get connected to smarter stats website by by passing the login window and load the statistics in a fancybox page
so far this is my code: but that does not seems to be working
<cfhttp method="post" url="https://stats.ezhostingserver.com/" resolveurl="true" redirect="true">
<cfhttpparam type="FORMFIELD" name="ctl00$MPH$txtUserName" value="test.ca">
<cfhttpparam type="FORMFIELD" name="ctl00$MPH$txtPassword" value="mypwd!">
<cfhttpparam type="FORMFIELD" name="ctl00$MPH$txtSiteId" value="12343">
</cfhttp>
<cfif cfhttp.statuscode EQ '200 OK'>
<cfhttp result="results" url="https://stats.ezhostingserver.com/default.aspx"/>
<cfoutput>
#results.filecontent#
</cfoutput>
</cfif>
problem is every time i load the page
http://domain.in/index.cfm
it comes back to
http://domain.in/stats/Login.aspx
I am using hostek website's stats provide for a domain
The reason your code is behaving this way is because the initial URL you have in your cfhttp tag is returning an HTTP 302 redirect. Then because you have the redirect attribute of the cfhttp tag set to true it is actually performing the redirect. Look at the documentation for that attribute:
redirect - If the response header includes a Location field AND ColdFusion receives a 300-series (redirection) status code, specifies whether to redirect execution to the URL specified in the field:
yes: redirects execution to the specified page.
no: stops execution and returns the response information in the cfhttp variable, or throws an error if the throwOnError attribute is True.
The cfhttp.responseHeader.Location variable contains the redirection path. ColdFusion follows a maximum of four redirects on a request. If there are more, ColdFusion functions as if redirect = "no".
Note: The cflocation tag generates an HTTP 302 response with the url attribute as the Location header value.
So instead of using that initial URL for your cfhttp request, try using the URL it is redirecting to. And set the redirect attribute to false. But be aware that having that attribute set to false the tag will throw an error if it gets a redirect status code so you will need to handle that.
Example:
<cfhttp method="post"
url="https://stats.ezhostingserver.com/Login.aspx"
resolveurl="true"
redirect="false">

Encoding E-Mail Addresses: EncodeForHTML or EncodeForURL

When a user registers on a site, should we use EncodeForHTML() or EncodeForURL() before storing the value in a DB?
The reason I ask this is that when I send an e-mail to someone that includes a URL that contains an email address as a URL variable, I have to use EncodeForURL(). But if this email address is already encoded using EncodeForHTML(), it will mean I have to Canonicalize() it before using EncodeForURL() on it again.
I would therefore think that EncodeForURL() is probably good, but is it 'safe' and 'correct' when storing the value in a database?
Update: Upon reading the docs it says that EncodeForURL is only for using a value in a URL. Thereofore it seems to make sense that I should store it as EncodedForHTML, but then Canonicalize and re-encode for URL when using it in a URL context. I don't know how much of a performance hit all this encoding is going to take on my server...??
Copying this from my company's internal documentation. Not sure if the images uploaded correctly since imagr is blocked # work. If so, I'll re-upload them later. I'll be publishing this and more related content to a Githib repo in the future.
You should store it as simple text, but make sure you scrub your data on the way in using an AntiSamy library. Once the data is safe, make sure to encode the data on the way out using the proper encoder. And FYI, there's a big difference between the output of encodeForHTML() and encodeForHTMLAttribute().
In the below examples, substitute the variables that define email addresses with data from the DB.
PROTIP: Don't use these encoders in CFFORM tags. Those tags take care of the encoding for you. CF 9 and below use HTMLEditFormat(), CF 10 and above most likely use encodeForHTMLAttribute().
Simple Implementation
A basic implementation is to include a single e-mail address in order to populate the "To" field of a new e-mail window.
CFML
<cfset email = "someone#example.com" />
E-mail
HTML Output
E-mail
CFML with Proper Encoding
<cfset email = "someone#example.com" />
E-mail
Encoded HTML Output
Notice that the "#" symbol is properly percent encoded as "%40".
E-mail
Results when clicked
And if you plan on showing the e-mail address on the page as part of the link:
<cfset email = "someone#example.com" />
#encodeForHTML(email)#
Attack Vector
An advanced implementation includes e-mail addresses for "To" & "CC". It can also pre-populate the body and subject of the new e-mail.
CFML without encoding
<cfset email = "someone#example.com" />
<cfset email_cc = "someone_else#example.com" />
<cfset subject = "This is the subject" />
<cfset body = "This is the body" />
E-mail
HTML Output
E-mail
Results when clicked
Notice that the subject and body parameters contain spaces. While this string will technically work, it is still prone to attack vectors.
Imagine the value of body is set by the result of a database query. This record has been "infected" by a malicious user and the default body message has an appended "BCC" address, so some evil user can get copies of e-mails sent via this link.
Infected Data
<cfset body = "This is the body&bcc=someone#evil.com" />
HTML Output
E-mail
Results when clicked
In order to stop this MAILTO link from being infected, this string needs to be properly encoded.
CFML with HTML Attribute Encoding
Since "href" is an attribute of the <a> tag, you might think to use the HTML Attribute encoder. This would be incorrect.
<cfset email = "someone#example.com" />
<cfset email_cc = "someone_else#example.com" />
<cfset subject = "This is the subject" />
<cfset body = "This is the body&bcc=someone#evil.com" />
E-mail
HTML Output
E-mail
Results when clicked
CFML with URL Encoding
The correct encoding of a MAILTO link is done with the URL encoder.
<cfset email = "someone#example.com" />
<cfset email_cc = "someone_else#example.com" />
<cfset subject = "This is the subject" />
<cfset body = "This is the body&bcc=someone#evil.com" />
E-mail
HTML Output with Correct Encoding
Notice these things about the URL encoder:
Each space (" ") is converted to a plus sign ("+") instead of its expected percent value ("%20").
Encoding is otherwise done using percent ("%") values.
Since the individual query paramters are encoded, the ampersands ("&") connecting each paramter were not encoded.
When the "body" paramter is encoded, it includes the "&body=" string that was maliciously injected. This entire string is now part of the message body, which prevents the unintended "bcc" of the e-mail.
E-mail
Results when clicked
What's with the plus signs? It is up to the individual mail client (e.g. Outlook, GMail, etc.) to correctly decode these URL encoded values.
Store the email addresses in plain text, then encode them when you use them, depending on the context. If it's going to be a part of URL, use EncodeForURL(). If it's going to be displayed in HTML as text, use EncodeForHtml().

DocuSign API with ColdFusion

UPDATED WITH WORKING SOLUTION
I'm trying to integrate the DocuSign API using ColdFusion and keep running into an issue. I am able to authenticate successfully and retrieve the base URL. However, when trying to create the envelope with a single recipient and document, I get an error stating that the "boundary terminator" is not found in the request (when it clearly is).
I know this questions is similar to another post here but that was from a while ago and was never completely answered.
I first read in the PDF document:
<cffile action="READBINARY" file="Agreement.pdf" variable="docData">
<cfset docData = BinaryEncode(docData,"Base64")>
I then create the envelope definition in XML using the element to include the encoded binary PDF data:
<cfset envelope = "<envelopeDefinition xmlns=""http://www.docusign.com/restapi"">
<status>Sent</status>
<emailSubject>eSignature request</emailSubject>
<emailBlurb>Please sign the document</emailBlurb>
<recipients>
<signers>
<signer>
<recipientId>1</recipientId>
<name>eCS Buyer</name>
<email>XXX#XXXX.com</email>
<tabs>
<signHereTabs>
<signHere>
<documentId>1</documentId>
<pageNumber>3</pageNumber>
<xPosition>10</xPosition>
<yPosition>100</yPosition>
</signHere>
</signHereTabs>
</tabs>
</signer>
</signers>
</recipients>
<documents>
<document>
<name>Agreement.pdf</name>
<documentId>1</documentId>
<fileExtension>pdf</fileExtension>
<documentBase64>#docData#</documentBase64>
</document>
</documents>
</envelopeDefinition>">
Lastly, I POST the information:
<cfhttp url="#baseURL#/envelopes" method="POST" resolveurl="Yes" throwonerror="No">
<cfhttpparam name="X-DocuSign-Authentication" type="HEADER" value="<DocuSignCredentials><Username>#userName#</Username><Password>#password#</Password><IntegratorKey>#integratorKey#</IntegratorKey></DocuSignCredentials>">
<cfhttpparam name="Content-Type" type="HEADER" value="application/xml">
<cfhttpparam name="Accept" type="HEADER" value="application/xml">
<cfhttpparam name="Content-Length" type="HEADER" value="#Len(envelope)#">
<cfhttpparam name="request_body" type="BODY" value="#envelope#">
</cfhttp>
I tried changing the TYPE attribute for the request body to XML and FORMFIELD but is still doesn't work. I even tried changing the envelope to JSON format to no avail.
The error that is generated is:
<errorCode>INVALID_REQUEST_BODY</errorCode><message>The request body is missing or improperly formatted. The XML request does not match the expected format. </message></errorDetails>
I have been struggling with this for weeks. Any guidance would be GREATLY appreciated.
Most likely an issue with extra CRLF (i.e., extra line breaks). See the answer in this other forum post for an example of what the full request structure should look like: Docusign : Unable to create envelope from document in restapi v2.
UPDATE #1
Looks like your XML request body is missing information about the Document. Try adding a documents element as a child element of envelopeDefinition (i.e., as a peer element to recipients):
<envelopeDefinition xmlns=""http://www.docusign.com/restapi"">
...
<documents>
<document>
<name>Agreement.pdf</name>
<documentId>1</documentId>
</document>
</documents>
...
</envelopeDefinition>
Also, make sure the document bytes that your sending in the subsequent part of the request are not encoded.
UPDATE #2
I don't know much about ColdFusion, but this line of your code makes it look like you're (base64) encoding the byte stream that you're including in the Request:
<cfset docData = BinaryEncode(docData,"Base64")>
This could be causing your latest issue, as I don't believe DocuSign will accept an encoded byte stream when it's included in the manner you're currently utilizing.
If you must base64-encode the byte stream, you could add a documentBase64 property under the document element to contain the base64-encoded byte stream. (See page 104 of the DocuSign REST API Guide -- http://www.docusign.com/sites/default/files/REST_API_Guide_v2.pdf.) If you utilized this approach, your request would no longer need to be a 'multipart' request, since the document bytes would be included in the XML portion of the Request Body (not in a subsequent/separate part). Here's an example of what the Request would look like, if the base64-encoded byte stream was included within the documentBase64 element:
POST /restapi/v2/accounts/ACCOUNT_NUMBER/envelopes HTTP/1.1
Host: demo.docusign.net
X-DocuSign-Authentication: {"Username":"SENDER_EMAIL_ADDRESS","Password":"PASSWORD","IntegratorKey":"INT_KEY"}
Content-Type: application/xml
<envelopeDefinition xmlns="http://www.docusign.com/restapi">
<accountId>ACCOUNT_ID</accountId>
<status>sent</status>
<emailSubject>eSignature request</emailSubject>
<emailBlurb>Please sign the document</emailBlurb>
<recipients>
<signers>
<signer>
<email>johnsEmail#outlook.com</email>
<name>John Doe</name>
<recipientId>1</recipientId>
<routingOrder>1</routingOrder>
<tabs>
<signHereTabs>
<signHere>
<documentId>1</documentId>
<pageNumber>1</pageNumber>
<xPosition>10</xPosition>
<yPosition>100</yPosition>
</signHere>
</signHereTabs>
</tabs>
</signer>
</signers>
</recipients>
<documents>
<document>
<name>Agreement.pdf</name>
<documentId>1</documentId>
<fileExtension>pdf</fileExtension>
<documentBase64>BASE64-ENCODED-BYTE-STREAM</documentBase64>
</document>
</documents>
</envelopeDefinition>
Since the document bytes are included within the XML portion of the request, the request no longer needs to be multi-part -- simply pass the XML Request body as I've shown above, and that's it.
The error is most likely due to the extra CRLF you have after the document bytes and before your closing boundary --MYBOUNDARY--. You have this:
#docData#
--MYBOUNDARY--
Try changing that to this without that extra CRLF:
#docData#
--MYBOUNDARY--
For reference you can check out the DocuSign API Walkthrough for sending a signature request on a document. Each of the different language versions shows you how the outgoing request body should be formatted.