I am using Braintree for payment gateway and I have across an issue.
I am sending credit card information with other user details.
For security purposes Credit card information has to be encrypted and it is being done by Braintree by including following:
braintree.onSubmitEncryptForm('braintree-payment-form');
This works fine until I use pure javascript (AngularJS) in front-end and I'm seeing that data is not encrypted while sending to server,
Here is code:
<form name="paymentForm" ng-submit="submitUser(userDetails)" method="post" id="braintree-payment-form">
<p>
<label style="color:white">Name</label>
<input type="text" ng-model="userDetails.userName" name="userName" size="20" />
</p>
<p>
<label style="color:white">Email</label>
<input type="text" ng-model="userDetails.email" name="email" size="20"/>
</p>
<p>
<label style="color:white">Company</label>
<input type="text" ng-model="userDetails.company" name="company" size="20" />
</p>
<label style="color:white">Card Number</label>
<input type="text" size="20" ng-model="userDetails.number" autocomplete="off" data-encrypted-name="number" />
</p>
<p>
<label style="color:white">CVV</label>
<input type="text" size="4" ng-model="userDetails.cvv" autocomplete="off" data-encrypted-name="cvv" />
</p>
<p>
<label style="color:white">Expiration (MM/YYYY)</label>
<input type="text" size="2" ng-model="userDetails.month" data-encrypted-name="month" /> / <input type="text" size="4" ng-model="userDetails.year" data-encrypted-name="year" />
</p>
<input type="submit" id="submit" />
On form submit, I am sending data to server.
$scope.submitUser = function(userDetails){
$http({
url: '/createtransaction',
method: 'POST',
data: JSON.stringify(userDetails),
headers: {'Content-Type': 'application/json'}
}).success(function (data, status, headers, config) {
// success
}).error(function (data, status, headers, config) {
//error
});
}
Is there anyway I can encrypt card details?
The question is "why is the AJAX request data not encrypted by Braintree JS", and the answer is nothing to do with HTTPS.
Yes, HTTPS is required to encrypt traffic in production - and in this case it will encrypt the already encrypted card data - but HTTPS is neither the question nor the answer here.
If you look at the Braintree documentation (Example here) you'll note that each input in the example form has added an attribute data-encrypted-name:
<input type="text" size="20" autocomplete="off" data-encrypted-name="number" />
The documentation then points out this code:
braintree.onSubmitEncryptForm('braintree-payment-form');
When the form is submitted, code in braintree.js is invoked, inspects the form, looks at the plain text in each marked input, encrypts it, save those encrypted values according to the data--encrypted-name attributes, and then that encrypted data is used when the form is transmitted via HTTP/HTTPS.
In the AngularJS example code above, the OP does include the data-encrypted-name attributes on some of the inputs (I don't know if it needs to be on all of them) but just labeling the input is not enough. The function to encrypt the raw input values (or in this case, the model data) still needs to be invoked, and then that encrypted model can be sent in a POST back to the server.
Said another way, the problem implementation:
Form builds a model
Model sent via HTTP to server
The corrected implementation would be:
Form builds a model
Braintree.js invoked to encrypt some parts of the model.
Encrypted model is sent via HTTP (or HTTPS in production) to server
Here's a plunkr someone else did showing one way to encrypt AngularJS model data on the fly:
http://plnkr.co/edit/2kF9Im?p=preview
If it were me, I'd just call braintree.encrypt() on each field immediately prior to submitting the form rather than on every keypress - or modify the directive to work on the form at submission time.
If your html page is accessed using HTTPS then your form submission will be (unless otherwise specified) be HTTPS. If you want to ensure that HTTPS is used, then you would need to do something on server to disallow HTTP for this particular page.
Related
I’ve got a simple HTML form that represents data of the User objects on the backend side. On the server, there’s a Spring boot application with a rest controller.
Here is the form:
<form id="new-user-form">
<label class="text-center col-form-label"><b>First Name:</b></label>
<input type="text" id="firstname" name="firstname" value="" />
<label class="text-center col-form-label"><b>Last Name:</b> </label>
<input type="text" id="lastname" name="lastname" value="" />
<label class="text-center col-form-label"><b>Age:</b></label>
<input type="number" id="age" name="age" value="" />
<label class="text-center col-form-label"><b>E-mail:</b></label>
<input type="email" id="email" name="email" value="" />
<label class="text-center col-form-label"><b>Password:</b></label>
<input type="password" id="password" name="password" value="" />
<label class="text-center col-form-label"><b>Role:</b></label>
<select class="col-12 form-control" name="roles" multiple size="2">
<option>ADMIN</option>
<option>USER</option>
</select>
<button
type="submit"
id="submit-new-user"
class="btn btn-primary btn-success"
>
Add new user
</button>
</form>
So, I need to take user data from the form, send it to the server via feth API, and put it to the database.
The first question is: how to serialize form data (using js) to JSON meaning that it has value represented by Set (roles)?
I guess, JSON object to be sent via fetch, should look like this:
{ “firstname”: “Bob”,
“lastname”: “Marley”,
“age”: 30,
“email”: “bob#mail.com”,
“password”: “password”,
“roles”: [“ADMIN”, “USER”] // or just [“USER”] or [“ADMIN”]
}
How can I take data from the form and get such JSON?
Which is the best way to convert incoming in request body User JSON-data to the User java-object in rest controller? I’ve tried via Gson and Object mapper but didn’t succeed. So far I iterate via JSON string and build new users from JSON keys and values, but this approach seems to be too complicated. This is the fourth day I’m trying to resolve this issue, please, I need help!
There are a few things to consider here:
1- Creating a JSON from your form content inside your JS file, before submission:
Example:
function onSubmit( form ){
var data = JSON.stringify( $(form).serializeArray() );
console.log( data );
return false; //don't submit
}
Ref: Serialize form data to JSON
2- Send Created JSON using Fetch API (Post) towards your backend springboot application
const response = await fetch("backend:8080/api/user", {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: data // <-- Must be in JSON format
});
3- Your backend Springboot application needs to have a Controller with a an endpoint that accepts this call.
Your User pojo needs to be defined in the backend application as well.
public class User{
#JsonProperty("firstName")
private String firstName;
#JsonProperty("lastName")
private String lastName;
}
#RestController
#RequestMapping(value = "/api")
public class EmailControllerImpl {
#PostMapping("/user")
public ResponseEntity<String> addUser(#RequestBody User userPojo){
//Deal with your User
}
Springboot will de serialize the JSON string you sent into the User pojo class on its own. You dont have to do anything at all.
You do need the following dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
I am new to this whole concept, so I am sorry if I am asking a basic question.
My HTML page has following form element,
<form method="POST" action="/:user">
<label>user :<label>
<input type="text" id="user" name="user">
<label>password :</label>
<input type="password" id="password" name="password">
<button> Submit <button>
</form>
My part of nodejs code from server side when calling this post method is:
app.post('/:user',(req,res)=>{
console.log(req.params.user);
})
All excluding this HTML element are working fine.
In the above HTML code, let's say if I give user input some name as " john", my idea is that it should call the router mentioned in the below nodejs code on the server-side.
But the way it is working is, it is calling the '/:user' rather than calling the '/'.Please help me how to change the action in the form element in HTML above, so as to have the desired output. By the way, I'm using ejs framework for HTML.
I've got a login form with two input fields: username and password.
<form method="post" action="testPwd.html">
<p>
<input type="text" name="username" value="" placeholder="username" maxlength="30"></p>
<p>
<input type="password" name="password" value="" placeholder="password" maxlength="25"></p>
<p class="submit">
<input type="submit" name="commit" value="Enter">
</p>
</form>
Once the user submits the form, his username and password are shown in the browser's network attribute in form data section
Request URL: http://localhost:8090/test/testPwd.html
Request Method: POST
Status Code: 302 Moved Temporarily
username: admin
password: admin
I don't want his username and password to be on display.
How can I do this?
That is an expected behavior. You can always see what parameters are passed to POST method (or any method for that matter)
However, you do not want the inputs to be readable to normal human eye, you can encode the username and password before passing them to the API and decode at the server side before using them.
Below is a very simple example. It does not guarantee anything but it will make the values not readable.
var encodedUsername = window.btoa(username); // encode username
var encodedPassword= window.btoa(password); // encode a password
var decodedUsername = window.atob(encodedUsername); // decode username
var decodedPassword = window.atob(encodedPassword); // decode password
Sort of a weird situation here. I'm building a backend and frontend which talks to a third party RESTFUL API that controls some hardware. The third party api is installed on your local system as a webserver, so to make HTTP requests you would direct them towards "localhost".
The main problem is after some changes the hardware has to be updated by logging into the webserver and clicking the "update hardware" button, this pushes all the newest changes to the actual hardware. Unfortunately the API doesn't have any default calls/commands for doing this.
After running through the files I found that I can refresh a door by simply making a GET request tohttp://localhost/IntelliM/DoorsConfig/DownloadChangeForAllDoors.ashx
If I enter this into my browser it updates the hardware perfectly.
The problem is that access to this page requires a login, which I've been trying to achieve through this code
/* update door */
router.get('/updatedoor', function (req, res) {
request.post({
headers: {'content-type' : 'application/x-www-form-urlencoded'},
url: "http://localhost/IntelliM/login/index.ashx?",
body: "password=admin&username=admin"
}, function(error, response, body){
//Here is where I would make a GET request to doorupdate mentioned earlier
console.log(body);
});
});
When I log the body, or have it displayed on a page, I get a large body response with most of it not really mattering besides these two lines:
Username: <input type="text" id="username" name="username" value="" />
Password: <input type="password" id="password" name="password" value="admin" />
It looks like the page isn't even getting my "username" value and just returning the body of the page I would get with only the "password" input filled in.
I'm trying to get it to log the page I would normally see after logging in, because then I would know the login worked and I could then make a GET request to the page I need to.
EDIT: For context the hardware is a door controller and the changes that have to be pushed are adding a user that can access a door.
EDIT FULL BODY:
<form id="loginForm" action="/IntelliM/login/login.ashx" method="post">
<fieldset id="loginFieldSet">
<legend id="loginFieldSetLegend">Authentication</legend>
<div id="loginFieldSetFields">
<p id="loginFieldSetUsername">Username: <input type="text" id="username" name="username" value="" /></p>
<p id="loginFieldSetPassword">Password: <input type="password" id="password" name="password" value="admin" /></p> <input type="hidden" id="ReturnUrl" name="ReturnUrl" value="/IntelliM/default.aspx" />
<p id="loginFieldSetButton"><input type="submit" value="Login" id="submit" /></p>
</div>
</fieldset>
<div id="loginFormRegister">Your system is licensed for Intelli-M Access</div>
Change url to /IntelliM/login/login.ashx and add change body to
form: {password="admin", username="admin", ReturnURL:"/IntelliM/default.aspx"}
So for example I have a simple HTML form:
<h3>
Login
</h3>
<div id="tabs-login">
<form method="get" action="./dev.html">
<fieldset>
<legend>
Email:
</legend>
<input type="text" class="required email" name="login" />
</fieldset>
<fieldset>
<legend>
Password:
</legend>
<input type="password" class="required" name="pass" />
</fieldset>
<input type="submit" value="Submit" />
</form>
</div>
And I use jQuery to validte it:
<script>
$(document).ready(function() { $("form").validate(); });
</script>
I want on form submition to take user inputed password value and take SHA256 from it via this jQuery plugin and submit email=user-inputed-value and pass=sha-value. How to access validated values via jQuery and change them and send to original form destination?
First -- I want to point out that I don't think this is a good idea. It's generally a bad idea to implement password hashing on the client side. Instead, the pass should be sent in plain text (over HTTPS) to the server, where it is then hashed using your preferred algorithm before storage. This has the added benefit of not advertising to potential attackers which hashing method is used, since that code exists only on the server.
That said: you're going to want to calculate that SHA value prior to form submit.
You could bind an event handler to the password field's blur event to update a hidden field's value with the new hash. Or you could add the update logic to the validation code.
Regardless of where the extra code goes, it will be much easier for you to prepare the hash prior to the form submit than it will be to send a second submission chasing after the first.
E.g.
<!-- add this to the form -->
<input type="hidden" name="sha_pass" value="" />
// add this to the document ready handler
$('[name=pass]').blur(function() {
$('[name=sha_pass]').val($.sha256($(this).val());
});