Opayo 3ds2 - sagepay PI integration rsa3dsauth.co.uk fails to return the threeDSSessionData - opayo

Opayo returns from our payment request asking us to contact https://www.rsa3dsauth.co.uk/3ds2/cReqWebBased?issuer=barclays" for 3D Secure auth, so we send this:
<form id="c-form" method="POST" action="https://www.rsa3dsauth.co.uk/3ds2/cReqWebBased?issuer=barclays">
<input type="hidden" name="creq" value="*removed for data protection*" />
<input type="hidden" name="threeDSSessionData" value="tQtpVHCcCVGEhPNDaeCtMK9I%2fREJERnarovmuZPsM4M6xy6gks9rOYix36waoxOn1wukcobCFbfd2jpmVDVDwZjrd3MzJtmpyFDEAu5R9azVveH6kBEXc5F2ETnFijQfEj5l6EzmH7EnMzbTlFHgbkDGR%2fH9CtURo0K2VSUKHN4%3d" />
<script>
document.addEventListener("DOMContentLoaded", function()
{
var b = document.getElementById("c-form");
b && b.submit();
});
</script>
</form>
And we get back
POST https://xxxxx.xxxxxxx.xxx/api/payment/3dsecurechallenge?eid=ctl00_cphMain_Payment_SagePay_ThreeD
cres=*removed for data protection*&threeDSSessionData=
Note there is nothing following &threeDSSessionData=, where it should be returning our string back to us.
The documentation says:
Anyone else having this issue?

Just to add some more context - we had the same issue but only with rsasecure.co.uk at the start of June. Other banks worked correctly. We have an open case with Opayo about this but there has not been a lot of communication.
We turned off 3DS while this issue is occurring but have been advised to try again today (23.07.21) as it may have been an issue at the banks side.

threeDSSessionData seems to be URL encoded in the input tag. Have you tried this without the URL encoding? I believe it should only be base64 encoded.

I've now received a response from Opayo. I also think they may have changed something because I'm positive I tried this previously and it didn't work...
threeDSSessionData is the base64 encoded of VPSTxId (including the curled braces). It is not base64url encoded - talking about url encoding is a massive red herring because the browser auto submit handles this without us having to do anything.
Here's an example that worked for me.
I curl post the card details to vpsdirect-register.vsp (or whatever flavour you're using). This must include a ThreeDSNotificationURL value that contains the URL of the your callback page.
The following response was received.
Status=3DAUTH
StatusDetail=StatusDetail=2021 : Please redirect your customer to the ACSURL, passing CReq.
VPSTxId={1F3F8015-FFEB-E897-0643-58841AD5DB03}
ACSURL=https://test.sagepay.com/3ds-simulator/html_challenge
CReq=ewogICJtZXNzY...iA6ICIwNSIKfQ
I base64 encode the VPSTxId value into a threeDSSessionData value and get the customers browser to autosubmit the following form
<form action="https://test.sagepay.com/3ds-simulator/html_challenge" method="post" id="autopostform">
<input type="hidden" name="threeDSSessionData" value="ezFGM0Y4MDE1LUZGRUItRTg5Ny0wNjQzLTU4ODQxQUQ1REIwM30=">
<input type="text" name="creq" value="ewogICJtZXNzY...iA6ICIwNSIKfQ">
</form>
Customer will then do the necessary gubbins and the callback URL will have something similar to the following posted to it
cres=ewogICJtZXNzYWd...OiAiWSIKfQ
threeDSSessionData=ezFGM0Y4MDE1LUZGRUItRTg5Ny0wNjQzLTU4ODQxQUQ1REIwM30=
Both of these values are base64 encoded (the cres actually contains the acsTransID that was in the original response). We now need to base64 decode the threeDSSessionData back into a VPSTxId which we then need to curl post along with the (still encoded) cres value.
VPSTxId={1F3F8015-FFEB-E897-0643-58841AD5DB03}
CRes=ewogICJtZXNzYWd...OiAiWSIKfQ
Hopefully that'll give us a successful response and the transaction should go through.
In short it's a complete pita. In reality the encoding element should be dealt with via Opayo's API rather than us needing to code this up.
Edit: Original Reply
Yes! We flicked over to v4 with 3DSv2 last week and have had a couple of dozen customers reporting that they try to pay, and basically just returned back to the checkout. Looking at one now for barclays, but have had others too - including one where they 3dauth and don't get returned to our checkout at all...

Related

Handling post request with form data with multiple identical names in jsp

On the website a ajax post request is send to a jsp file, that reads the body and sends back a response that is used to refresh a part of the page. In the Ajax request I can see that the data with identical names is send. However, I can not read the data. With unique names I can retrieve the data in jsp. Changing the way the data is send is not an option, because there is too much code build around it.
This code reads the form data and prints it back on the website.
<h1>Facet <c:out value="${pageContext.request.getParameter('facet')}" /></h1>
<h1>Minprice <c:out value="${pageContext.request.getParameter('minPrice')}" /></h1>
"Minprice" is printed to the screen, but "Facet" isn't.
I found it! The request class has a different method for handling multiple identical parameter names, like which is often the case with the <select> and <option> tags. It is the "getParameterValues()" method. The following code gives me the result I was looking for.
<c:forEach items="${pageContext.request.getParameterValues('facet')}" var="item">
<h1>Facet ${item}</h1>
</c:forEach>

Php session variable instead of GET method

I have a form that has name, Id, address etc. It needs to refresh after user enters the ID inorder to query and retrieve other information such as major based the entered ID.
Once it refreshes, I retrieve back the entered values via Get method so to retain the entered form values.
Shown below
<?php
$_SESSION['Bid']=#$_GET['Bid'];
$_SESSION['Stufname']=$_GET['fname'];
$_SESSION['Stulname']=$_GET['lname'];
?>
<form name="form1" method="post" action="registration.php" >
<input type="text" name="Bid" value="<?php echo $_SESSION['Bid'];?>"
MAXLENGTH=9 size="9">
</form>
All works fine but i know GET method is unsecure since the variables are now shown in the URL and I want to get away from using get.
I tried session variable in other scripts but in this case, because the page refreshes after entering ID, I am not really sure how to capture and store the form values in the session variables on page refresh without using the GET method as I did above.
Any help would be appreciated.
thanks,
You can use POST rather. You'll be able to figure out the syntax from here: http://www.w3schools.com/php/php_post.asp but I'd recommend doing more research before posting a question.

Does CodeIgniter's CSRF protection alter the value/name of hidden inputs while recovering data?

A quick intro to CodeIgniter 2 CSRF protection
I know this might sound dumb, but I'm wondering if this protection alters the value of the hidden input when you try to recover it by post.
Here's a quick example to show you what the protection does.
If I write :
<input type='hidden' name='1_Info".$kid_nb."' value='".$code."'>
It will output on the page :
<input type="hidden" value="0d3a7bb9f93f438dda1f605d2ac2cb7c" name="csrf_test_name">
Protection is good. But am I going to recover the right data when I use POST method on that input? Moreover, the value of $code is CodeIgniter-encoded ( using their library ). Is it going to mess it up ?
Finally, can I still reach that input, considering his name has been changed ? I know this might sound dumb, since a good protection wouldn't stop me from using my data, but it's always better to ask, right ?
Thanks, as usual. I'm merely a student.
I think there's some confusion. Codeigniter does NOT overwrite your variables: hidden or not. If you enable CSRF protection, framework will ADD another hidden field and check that token on submission. You still have your variables in the form and can process them the same way you normally would.
I don't see how
<input type='hidden' name='1_Info".$kid_nb."' value='".$code."'>
gets converted into
<input type="hidden" value="0d3a7bb9f93f438dda1f605d2ac2cb7c" name="csrf_test_name">
The latter would just get added to your list of form fields

URL shortening with POST data

Many services (eg, bit.ly) will shorten URLs, even those w/ GET data,
since that's just part of the URL.
Do any work w/ POST data? In some cases (eg, certain types of CBOE
option quotes), you must POST data to get the information you want.
The service might bring up a page (eg, shorten.com/foo) that has:
<form action="/url/to/post/to">
<input type="hidden" name="var1" value="val1">
...
<input type="submit" value="SUBMIT">
</form>
where the /url/to/post/to and var1/val1/etc are set by the person
creating the shortened URL. It would also say:
"By pressing the button below, you will post this data to this URL:
/url/to/post/to: [list of hidden fields and values]"
Seems useful and easy to do... has anyone done it?
OK, this seems to have degenerated into a moral argument. I'll assume the answer is no, no one has already done this.
I see two big problems:
Who is going to copy / paste the form (often generated by javascript) - Regular users? It would only be open to people with enough technical competence to do it. And it may not do not have the intended effects since some data may be in cookies or held server-side.
Also, post requests are not usually considered an open api for anyone to use. Usually, data is built up over a series of steps with possible use of cookies and login information. Websites are not going to be happy with letting people delete their account or bypass certain pages that are in the normal process flow.

Codeigniter: Pass form variable into URI

Not sure if this can be done but it seems my main issue is because i have a default route to a method called "index." I want to be able to list all users tagged with a specific keyword. In addition, users can search for other users based on these keywords.
i.e.
www.domain.com/tags/apples
www.domain.com/tags/oranges
www.domain.com/tags/blueberry
It works fine if I go to the URL manually. I'm having issues getting it to work with a form field.
Snippet of the form_open:
<?=form_open('tags/');?>
<p>Search for Tag: <input type="text" name="tag" /></p>
<p><input type="submit" value="Search" /></p>
Here's a snippet of my controller:
function index() {
$data['result'] = $this->tags_model->searchByTag($this->uri->segment(2));
$this->load->view('tags_view', $data);
}
Here's a snippet of my router:
$route['tags'] = "tags/index";
$route['tags/(:any)'] = "tags/index/$1";
Now, I can easily fix all this if I have a method called search, but I don't want the URL to show up as www.domain.com/tags/search/orange.
When you create your form you set it to use POST variables instead of GET, that way they don't go through the url, that's codeigniter's default method for forms.
So your form_open code will generate the following code:
<form method="post" action="tags/" />
If you want them to got through url though, call the form opener this way instead:
form_open('tags/', array('method' => 'get'));
The same applies to any other attributes you want to specify for the form, just follow the same pattern attribute_name => attribute_value inside the array.
More info on the user guide
The problem here is that your form will be submitting all it's data to "/tags", with nothing trailing it, as POST data doesn't come in as part of the URL. Even if it was a GET request however, I don't think that CodeIgniter will take anything out of the querystring and use it as part of the routing segments.
I think what you should do is have a small Javascript function that automatically updates the form action parameter to be tags/<select option value> whenever the select value is changed. This way it will submit to the right place. In order to handle non-javascript enabled browsers, you could have a default action called tags/search that would simply analyze your form data and put out a 301 redirect to the proper tags/<location> once you'd figured it out.
It seems like a bit of overkill here however, as you could really point the form at tags/index and not worry about it. I'm not sure search engines index form submission locations, and even if they did, they certainly wouldn't index a form that submits to dynamic URIs in the way that you want it to. You could still link to the search result pages using tags/apples, etc, but the form could work quite normally just by going to tags/index.
I ended up redirecting the URL and passed the keyword into the URI.
i.e. domain.com/tags/view/

Resources