I have for many Days i could not make http post request for the following site
http://www.imei.sy/imei
I don't know the principle behind that. I tried to make the request using GuzzleHttp, and curl.
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "http://www.imei.sy/imei",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "UTF-8",
CURLOPT_MAXREDIRS => 20,
CURLOPT_TIMEOUT => 60,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => array("_token:evsLRDom2AShHsioY5OyEB7cDU45opx8J0VLgqd2",//TgghCi5gkU6HODTyDwAWq0mvEyHC3ys8dXGskta1",
"imei:000000000000000"),
CURLOPT_HTTPHEADER => array(
"cache-control: no-cache",
"content-type: application/x-www-form-urlencoded",
"postman-token: 6a987964-86b8-25db-71a5-7c47822ec59c"
),
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
i can not reproduce the issue, when i run the code you provided, it executes the following POST request:
POST /imei HTTP/1.1
Host: www.imei.sy
Accept: */*
Accept-Encoding: UTF-8
cache-control: no-cache
postman-token: 6a987964-86b8-25db-71a5-7c47822ec59c
Content-Length: 295
Content-Type: application/x-www-form-urlencoded; boundary=------------------------4b99e3fabc390822
--------------------------4b99e3fabc390822
Content-Disposition: attachment; name="0"
_token:evsLRDom2AShHsioY5OyEB7cDU45opx8J0VLgqd2
--------------------------4b99e3fabc390822
Content-Disposition: attachment; name="1"
imei:000000000000000
--------------------------4b99e3fabc390822--
this is definitely a POST request in the multipart/form-data-format. (even tho the Content-Type header incorrectly claims that it's in the application/x-www-form-urlencoded-format, which makes servers unable to parse it properly.. but it's still a POST request nonetheless, it's just a severely malformed one.)
however note that code definitely won't be checking any IMEI code, because prior to checking a code, you must get a cookie and a CSRF token, the token won't work without the cookie and the cookie won't work without the token, but the token change for every cookie, and you can't hardcode it, but that's exactly what your code is trying to do,
your code won't work because:
it never creates a cookie session (required to check an IMEI)
it attempts to hardcode a CSRF token instead of fetching a dynamic token. (the CSRF token is tied to the cookie session.. which your code never creates in the first place.)
.. to check an IMEI here, first you have to enable cookie handling in curl, that can be done with CURLOPT_COOKIEFILE, also UTF-8 is not a valid transfer-encoding and makes no sense, instead do:
curl_setopt_array($ch,array(
// emptystring COOKIEFILE tells curl enable cookie-handling and save cookies in-ram
CURLOPT_COOKIEFILE=>'',
// emptystring encoding tells curl to automatically handle compression with all built-in compression algorithms (usually "gzip" and "deflate"), it makes compressible transfers faster
CURLOPT_ENCODING=>'',
CURLOPT_RETURNTRANSFER=>1,
));
next you have to fetch the page with a normal GET request, this will give curl the cookie needed to check an IMEI, and give curl the CSRF token needed to check an imei,
curl_setopt_array($ch,array(
CURLOPT_URL=>'http://www.imei.sy/imei',
CURLOPT_HTTPGET=>1
));
$html=curl_exec($ch);
if(empty($html)){
try{
throw new \RuntimeException("curl_exec() failed! ".curl_errno($ch).": ".curl_error($ch) );
}finally{
curl_close($ch);
}
}
after you got the cookie (which is handled automatically by curl), and the CSRF token in the HTML, you need to extract the token from the HTML, that can be done with DOMDocument and DOMXPath,
$domd=#DOMDocument::loadHTML($html);
$xp=new DOMXPath($domd);
$token=$xp->query("//input[#name='_token']")->item(0)->getAttribute("value");
and finally, now that you have both the session cookie and the CSRF token, you can do the IMEI lookup request,
curl_setopt_array($ch,array(
CURLOPT_POST=>1,
CURLOPT_POSTFIELDS=>http_build_query(array(
'_token'=>$token,
'imei'=>'999999999999999'
))
));
$html=curl_exec($ch);
if(empty($html)){
try{
throw new \RuntimeException("curl_exec() failed! ".curl_errno($ch).": ".curl_error($ch) );
}finally{
curl_close($ch);
}
}
curl_close($ch);
and to get the response from the HTML, one can again use DOMDocument,
$message=(#DOMDocument::loadHTML($html))->getElementById("sts")->textContent;
var_dump($message);
which yields:
$ php wtf2.php
string(100) " مُعرف الجهاز المُدخل غير صالح، الرجاء التحقق من الرقم "
because 999999999999999 was not a valid IMEI code.
Related
I am new to Svelte, and am trying to create a login page to an API. The API takes a username and password and returns an Authorization header. I see the authorization header in the F12 developer console, and I am able to access other headers via code, but not the Authorization header. I have enabled CORS on the server for localhost:8080.
<script>
const BASE_URL = ...;
export let username;
export let password;
let result;
let status;
let body;
let token;
let contentType;
async function doPost () {
const res = await fetch(BASE_URL + 'authenticate', {
method: 'POST',
mode: 'cors',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
'username': username,
'password': password
})
});
const text = await res.text();
status = res.status;
result = text;
token = res.headers.get('Authorization');
contentType = res.headers.get('Content-type');
if (!res.ok) {
throw new Error(result);
}
}
</script>
Please log in<br>
<input type="text" bind:value={username}/>
<br>
<input type="password" bind:value={password}/>
<br>
<button type="button" on:click={doPost}>Log in</button>
<br>
Result: {result}
<br>
Status: {status}
<br>
Token: {token}
<br>
Content-type: {contentType}
Response headers are as follows:
HTTP/1.1 200
Server: nginx/1.20.0
Date: Tue, 31 May 2022 18:59:09 GMT
Content-Type: text/plain;charset=UTF-8
Content-Length: 8
Connection: keep-alive
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: http://localhost:8080
Authorization: Bearer xyz...
The page displays as follows after logging in:
Result: Welcome!
Status: 200
Token: null
Content-type: text/plain;charset=UTF-8
Server side (spring boot) has the following annotation on the authenticate method:
#CrossOrigin(origins = "http://localhost:8080", allowedHeaders = "*", allowCredentials = "true")
As you can see, I am able to access the content-type header but not the authorization header. Any assistance would be greatly appreciated.
I figured it out. I needed to add exposedHeaders = "Authorization" to the #CrossOrigin annotation on the server side.
I literally solved this exact problem today. So... I'm not entirely sure why you cannot access the cookies sent back in the HTTP response, I believe it has something to do with not allowing js access to cookie related data for security reasons.
A preliminary issue I see, is that you should be sending the API auth token to the frontend, in the 'set-cookie' header, along with sending it in the HTTP response body, which I assume is JSON for your API.
I've never seen anyone suggest sending it in the 'Authorization' header like you have. I believe you are confused. I'll try and clarify the right way to do this and why you're most likely confused.
Your backend will generate an access token of some sort upon a successful login. Like I said, you send it back in the 'set-cookie' header, aswell as in the HTTP body.
Now when you read the response on the frontend, you can retrieve the Auth token from the HTTP response body, and use it in subsequent requests to authenticate to your backend server. The way JWT tokens are expected to be sent is in the 'Authorization' header of your request. This is where you're mixed up, the 'Authorization' header is used in subsequent authenticated requests to the server, not to send the Auth token from the backend to the frontend.
Now along with setting up the 'Authorization' header, you'll most likely need to send that same token in the 'cookie' header. You can do this by using the {withCredentials: true} option with fetch. This will send the cookie you sent in the 'set-cookie' response header after a successful login attempt, back to the server on all subsequent requests where you set this option.
Hope this helps, sorry I'm on my phone, so restricted with what I can write.
I am trying to fetch a public API. When I do it from the postman everything works fine however when I do it from my app I get and error message: <META NAME=\"robots\" CONTENT=\"noindex,nofollow\"
I do not understand how this is possible?
Here is are the headers variables I adjust when I make my request with postman:
Cookie:"some cookie"
Cache-Control: no-cache
Content-Type:application/json
Host:"some host"
Here is my httparty request:
response = HTTParty.post(url,
:body => body_request (same as with postman),
:headers => {
'Content-Type' => 'application/json',
'cookie' => 'same cookie as above',
'Host' => 'same host as above',
'Cache-Control' => 'no-cache'
}
)
Why would it work with postman but not with a httparty request?
Thank you
I would look into User-Agent, even if you don't explicitely set the header, your http client is still sending one.
Postman uses :
"User-Agent": "PostmanRuntime/7.26.8",
while HTTParty is simply
"User-Agent": "Ruby"
Maybe your public API (could be more precise if we knew which) has a whitelist of 'non-bot' user agents and HTTParty is not among them
Try overriding it
resp = HTTParty.get 'https://httpbin.org/headers' , headers: {'User-Agent': 'xx'}
I'm trying to automate actions I can take manually in an iPhone app using Ruby, but when I do, I get a 502 bad gateway error.
Using Charles Proxy I got the request the iPhone app is making:
POST /1.1/user/-/friends/invitations HTTP/1.1
Host: redacted.com
Accept-Locale: en_US
Accept: */*
Authorization: Bearer REDACTED
Content-Encoding: gzip
Accept-Encoding: br, gzip, deflate
Accept-Language: en_US
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Content-Length: 66
Connection: keep-alive
X-App-Version: 814
invitedUserId=REDACTED&source=PROFILE_INVITATION
I wrote the following code in Ruby to send this same request:
#header_post = {
"Host" => "redacted.com",
"Accept-Locale" => "en_US",
"Accept" => "*/*",
"Authorization" => "Bearer REDACTED",
"Content-Encoding" => "gzip",
"Accept-Encoding" => "br, gzip, deflate",
"Accept-Language" => "en_US",
"Content-Type" => "application/x-www-form-urlencoded; charset=UTF-8",
"Connection" => "keep-alive",
"X-App-Version" => "814"
}
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
path = '/1.1/user/-/friends/invitations'
data = "invitedUserId=REDACTED&source=PROFILE_INVITATION"
resp, data = http.post(path, data, #header_post)
Unfortunately I get a 502 Bad Gateway Error when running this code.
One thing I noticed which I think is key to the solution here is that, in the POST request the mobile app is making, the content length is 66. But the length of the string "invitedUserId=REDACTED&source=PROFILE_INVITATION" with un-redacted userId is only 46.
Am I missing another form variable with format "¶m=value" which has length 20? Or am I missing something else?
Thank you in advance!
This is probably not directly tied to the body length you're sending.
I see possibly 2 problems here :
the 502 error : are your uri.host and port correct ? A 502 error means there is something wrong on the server side. Also try by removing the Host header.
body content is not gzipped
You're defining an header Content-Encoding: gzip but you didn't compress the data (Net::Http doesn't do that automatically).
Try with something like that :
require "gzip"
#header_post = {
# ...
}
http = Net::HTTP.new(uri.host, uri.port)
path = '/1.1/user/-/friends/invitations'
data = "invitedUserId=REDACTED&source=PROFILE_INVITATION"
# instanciate a new gzip buffer
gzip = Zlib::GzipWriter.new(StringIO.new)
# append your data
gzip << data
# get the gzip body and use it in your request
body = gzip.close.string
resp, data = http.post(path, body, #header_post)
Alternatively, maybe the server is accepting a non-gzipped content. You could try simply by deleting the Content-Encoding
error from your original code.
However if it was the only mistake, the server should not send a 502 but a 4xx error. So I'm guessing there is another issue there with the uri config like a suggested above.
I am trying to access an API using Guzzle in Laravel 5.5.
The command in curl looks like:
curl http://apiurl.com/getRequest -d "api_key=token_value"
Now using Guzzle, I started to code as below:
$client = new Client(['base_uri' => 'http://apiurl.com/']);
$response = $client->request('GET', 'getRequest', [
'headers' => [
'api_key' => ['token_value']
]
]);
var_dump($response->getStatusCode());
var_dump(json_decode($response->getBody(), true));
Now I am able to see statusCode as 200 and getBody as Null. But when I use the same request using curl then I am able to see the complete data.
Could someone resolve it please?
When comparing differences between curl and Guzzle, I highly recommend using -v (curl) and the debug request option (Guzzle). The verbose output allows for visual comparison of the requests that each software is transmitting.
The curl man page indicates that -d and --data send POST requests.
(HTTP) Sends the specified data in a POST request to the HTTP server,
in the same way that a browser does when a user has filled in an HTML
form and presses the submit button. This will cause curl to pass the
data to the server using the content-type
application/x-www-form-urlencoded.
A pair of changes are required in order to send the desired request with Guzzle:
$response = $client->request('POST', $uri, [
'form_params' => [
'api_key' => $key_value,
],
]);
The first change is the type of request that is being sent (GET => POST). The second, is the usage of form_params. The form_params request option is used to send application/x-www-form-urlencoded POST requests.
I'm looking at a curl request that has the following as its header. What does this mean?
curl -H 'Authorization:token token="[SOME_VALUE]"' 'https://myurl.com'
Furthermore I'm trying to use RestClient to request this URL from ruby. https://github.com/rest-client/rest-client
Normally in headers it's just a key:value, but here this seems different.
It looks like the API you want to use is adopting the HTTP Token authentication RFC.
This document was a draft and it never turned into an official standard, but there are some APIs that are using it.
GET /resource/1 HTTP/1.1
Host: example.com
Authorization: Token token="h480djs93hd8",
coverage="base",
timestamp="137131200",
nonce="dj83hs9s",
auth="djosJKDKJSD8743243/jdk33klY="
You can pass custom headers to RestClient using the header option.
api_token = "xyz"
RestClient.get "http://example.com/resource", { :Authorization => %Q{token token="#{api_token}"} }
I used %Q to allow interpolation. If it's unclear to you, you can also use something like
api_token = "xyz"
RestClient.get "http://example.com/resource", { :Authorization => 'token token="%s"' % api_token }
It will be same as key value pair. Here the key is Authorization and the value is token token="[SOME_VALUE]". That should be something like below as ruby hash copied from here.
{:Authorization => 'token token="[SOME_VALUE]"'}
You can use some additional information in headers, not just key:value. For example:
Accept: text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c
Authorization:token token="[SOME_VALUE]" can be used with API with token based authentication.
Token based authentication is when an API client uses a token identifier to make authenticated HTTP requests.
You can read more about this type of authentication here: http://blog.codeschool.io/2014/02/03/token-based-authentication-rails/