I've searched this site and found how to programmatically log in to a website in C#. However, this specific site encrypts the password somehow before sending the form.
I snooped on several POSTs using Live HTTP Headers for Firefox and found:
Account=[REDACTED]&pw=a0c41f57ef14e43642269bb1e452ae40
Account=[REDACTED]&pw=17fd04959cdf6f44b799221fb9a2e0e3
The password that is sent changes every time.
As I press login, I can see the password change in the form.
I looked at the page source and it might use "MD5 encryption", however I don't know how I would call the function that encrypts it, and I don't know why it changes every time after researching MD5.
Here's the function:
function doLogin(form)
{
var originalpw = form.pw.value;
var b64pw = b64_md5(originalpw);
var hmac_md5pw = hex_hmac_md5(pskey, b64pw)
form.pw.value = hmac_md5pw;
form.dbpw.value = hex_hmac_md5(pskey, originalpw.toLowerCase())
if (form.ldappassword!=null) {
// LDAP is enabled, so send the clear-text password
// Customers should have SSL enabled if they are using LDAP
form.ldappassword.value = originalpw; // Send the unmangled password
}
return true;
}
EDIT:
Alright, now I'm running the javascript using Noesis.Javascript. It works perfectly, but one last thing is the "pskey" variable. It changes every time you load the login page, and I found where it is so I can Regex it from the page source.
HOWEVER:
How will the page know that the webclient that downloaded the html code for the pskey is the same one that sends the POST to login and also GETs the logged in page?
I have these requests:
GET login page for pskey
POST login
GET logged in page
How can I use the same WebClient for each?
Javascript can be run in C# by using Javascript.Net.
using Noesis.Javascript;
//...
string runJavascript(string str){
using (JavascriptContext context = new JavascriptContext())
{
//Set external variables:
context.SetParameter("var", str);
context.Run("function jsFunc(s) { //encode in here } str2 = jsFunc(var)");
Console.WriteLine(context.GetParameter("str2"));
return context.GetParameter("str2").ToString();
}
}
Related
Creating an intranet application, in which URL will be sent to the user via Email(outlook). This URL should be generated using cipher(need a randon URL based on his Email/Emp ID) and through this URL user should be able to login into account. The link should also have time validity. Example: link expires after 7 days.
What I have?
User's Email and Employee ID.
Any pointers, how to achieve the above task in C#? or Any other idea, because I just need to User to access application for certain time using Email only.
It seems that you have gotten it a bit mixed up. The URL cannot be encrypted with the ID or emai. There is little point in using as a key the Employee Id or the email since they are public information.
What you could do is create a random string for the URL and just use the two pieces of information to generate the string. However, once they visit the URL you will need to ask them for a secret password in order to log in. Just by visiting the URL and the inputting their email you achieve nothing in terms of security. It is trivial to break such a system by bruteforce if you have access to the emails/employee ids (which you must assume all have).
For the URL based on the email you can xor the two strings and send the output. Then xor the output with the email and get the url.
public static string xorIt(string email, string url)
{
StringBuilder sb = new StringBuilder();
for(int i=0; i < input.Length; i++)
sb.Append((char)(url[i] ^ email[(i % key.Length)]));
String result = sb.ToString ();
return result;
}
a way to check for validity is to store the url in a database along with a timestamp and check at the time of login if it still valid.
There are some caveats with the above approach (e.g. xor always produces the same output for the same two strings but this can be solved if you add a random string and store that string in the table above).
You can't lock this down to their e-mail only, because they could just copy & paste the URL into a browser.
Essentially to get the time-sensitive behaviour, you need to have the following:
A database table (or some form of storage) to indicate that this user has been issued a token, and when that token expires
A means to generate the cipher-url from the user's e-mail address.
Generating the URL part is easy, in pseudocode you could envision it being as such:
var user = GetUser("John.Doe#gmail.com");
var token = EncryptAndHashEmailAddress(user);
var entry = new TokenTableEntry(token:token, expires:DateTime.Now.AddDays(7), User: user.Id);
var url = #"https://www.mywebsite.com/login.aspx?token=" + token;
Then when the user clicks the link and hits whatever handles the login request:
var token = GetQueryParameter(0); // Get first query parameter
var entry = TokenTable.Element(e => e.Token == token);
TokenTable.Remove(entry);
if (DateTime.Now > entry.Expires)
{
// Their token has expired
GoTo("TokenExpired.aspx");
return;
}
LoginController.UserLoggedIn(entry.Id);
This is very rough psuedocode, but it should put you on the right tracks.
I have been using google+ APIs for C# in my desktop application.I have to access the friends list of the google+ user.
I have been obtaining access token by extracting it from browser title.
It works fine for the following permissions(all grouped and asked at same time) and returns the authentication code in browser title(success=authcode).
"https://www.googleapis.com/auth/plus.me
"https://www.googleapis.com/auth/youtube",
"https://www.googleapis.com/auth/youtube.upload"
But when i changed the permission to obtain the friends list,
"https://www.googleapis.com/auth/plus.login
it's not returning the desired auth code ,it just returns success authuser=0&promt...
By the way I can't listen on local web server.
How to obtain the access token by using the above permission?
I just checked this and the success string in the window title is in fact different when you are using the plus.login scope. The code that is returned in the string is still valid though. The following code shows one way you could extract the authorization code from the window title string:
string pollActiveWindowForAuthCode(int sleepTime){
string activeTitle = GetActiveWindowTitle();
while (!activeTitle.StartsWith("Success"))
{
activeTitle = GetActiveWindowTitle();
Thread.Sleep(sleepTime);
}
// strip to start of auth code
string trimToAuthCode = activeTitle.Substring(activeTitle.LastIndexOf("=") + 1);
// trim the " - Google Chrome" text
return trimToAuthCode.Substring(0, trimToAuthCode.IndexOf(' '));
}
I have uploaded a more comprehensive demo to my GitHub:
csharp-gplus-wpf
There are lots of sample applications in MVC but the current project I'm working on requires that I use web forms.
I can authorize the application using the javascript method but I want to use server side. Below is what I started with on the page.load
dynamic parameters = new ExpandoObject();
parameters.client_id = AppId;
parameters.client_secret = appSecret;
parameters.response_type = "code";
//parameters.state = state;
parameters.redirect_uri = "http://fb.local/page.aspx";
// The requested response: an access token (token), an authorization code (code), or both (code token).
parameters.response_type = "token";
// list of additional display modes can be found at http://developers.facebook.com/docs/reference/dialogs/#display
//parameters.display = "popup";
// add the 'scope' parameter only if we have extendedPermissions.
if (!string.IsNullOrWhiteSpace(ExtendedPermissions))
parameters.scope = ExtendedPermissions;
// generate the login url
var fb = new FacebookClient();
var loginUrl = fb.GetLoginUrl(parameters);
Response.Redirect(loginUrl.AbsoluteUri, true);
I can authorize but I'm not able to get the access token from the URL.
On the next page I can view source and see the access token in the url bar but I'm not sure how to go about getting it into the code. once I have the token, I'm all set.
page.aspx#access_token=AAACrxQhmdpY
I used to this code on my page load and works, its not a very clean code, but you may figure out how to change it for your best use. so the algorithm is that when the page loads you redirect the user to Facebook authentication page using response.redirect to a string that contains three parameters:your app ID(appid), what permissions you are asking your user(scope), where you want Facebook to redirect the user after authorization, and a parameter as state which i guess it should be a random number. so after the user authorized your application he/she will be redirected to your page, with a request URL that contains the same state you prepared Facebook with(and you can use to identify who which request was which if there are many requests i guess) and also a new "code" parameter which you pass on to Facebook to obtain access token, you can use Facebook c# sdk to obtain the access token.in my code there is a line that says "if code is not null, go to alireza" and alireza is a line tag after the response.redirect code, this is because you dont want the process to be repeated all over and over (and of course probably the browser show an error).
int intstate;
string strstate;
string redirecturltofb;
string scope;
string appid;
code = Request.QueryString["code"];
if (!String.IsNullOrWhiteSpace(code))
{
goto alireza;
}
appid = "424047057656831";
scope = "user_about_me,user_activities,user_groups,email,publish_stream,user_birthday";
intstate = 45;
strstate = Convert.ToString(intstate);
redirecturltofb = "https://www.facebook.com/dialog/oauth?client_id=" + appid + "&redirect_uri=http://test5-2.apphb.com/&scope=" + scope + "&state=" + strstate;
Response.Redirect(redirecturltofb);
You have to use Javascript SDK to get access token back to code behind.
Use FB.Init as in http://csharpsdk.org/docs/web/getting-started
and do post back on certain conditions to get the access token.
Thank you,
Dharmendra
I want to let people to log in with "Facebook login".
but, I wonder if it is secure enough, or I'm just doing it wrong.
What I'm getting back after a successful login is the user data, with the facebook_id, which I'm inserting to the DB passed by a JavaScript reuest to the server via handler since I'm using asp.net.
But, what I think that by a malicious use, one can change that data. and insert rubbish to the server, or even insert different facebook_id.
So I wonder if the "Facebook login" is secure enough to use, or that I'm doing it wrong.
I thought about other option to pass that client data to the server - by postback the server with a hidden runat=server textboxes but still, malicious use can change those textboxes. I've read here about the option to let the users add password to their Facebook username but it sounds a bit not user-friendly.
Am I right? is that a way to do it more secure? Is there any cookie that Facebook put on the client browser that I can read from the server? as though a lot of websites use this "Facebook login" there might be another way that I didnt think about...
Pass the access token up to the server (or check for it from the cookie Facebook sets) and then have the server call https://graph.facebook.com/me?access_token=... and get the Facebook ID that way. You can get the access_token by calling FB.getLoginStatus from the javascript sdk.
You can use oauth to transfer this operation to server side.
Have a look at this blog post:
http://you.arenot.me/2010/09/28/facebooks-graph-api-and-asp-net/
It is important to make an independent call from the server, especially if you are storing their facebook user id in a database or something. That way, you know whether or not it is valid.
First, after calling the FB.init function in the Facebook Javascript SDK, you want to get the user's access token and facebook user id via the Javascript SDK similar to this:
FB.getLoginStatus(function (response)
{
if (response.status === 'connected')
{
var token = response.authResponse.accessToken;
var facebookUserID = response.authResponse.userID;
}
});
Second, once you got a token and facebook user ID, you will want to pass those variables to your server. If you are using WCF or some other form of web service along with JSON.NET, you could create a method such as this:
[WebInvokeAttribute(BodyStyle = WebMessageBodyStyle.WrappedRequest, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
[OperationContractAttribute]
public Stream AuthenticateFacebook(string facebookUserId, string token)
{
var json = new WebClient().DownloadString(string.Format("https://graph.facebook.com/me?access_token={0}", token));
JObject parsedJson = JObject.Parse(json);
//Ensure that there isn't a random Facebook server error
if (parsedJson["error"] != null)
{
throw new FaultException("Error parsing Facebook token.");
}
//Ensure the facebook user ID passed in via the client matches the one received from the server.
if (Convert.ToString(parsedJson["id"]) != facebookUserId)
{
throw new FaultException("Facebook login ids do not match. Something fishy is going on...");
}
//Now you know you have a valid facebook login id. Do your database stuff or whatever else here.
}
You now have validated that the user is who they say they are.
I have some JavaScript that logs in a Facebook user and saves the access token to a database:
window.fbAsyncInit = function () {
FB.init({
appId: '<%=FaceBookApplicationId() %>',
status: false, // check login status
cookie: true,
oauth: true
});
};
function facebookLogin() {
FB.login(function(response) {
if (response.authResponse) {
__doPostBack('__Page', 'FacebookDeliveryButton: ' + JSON.stringify(response.authResponse));
} else {
console.log('User cancelled login or did not fully authorize.');
}
}, { scope: 'offline_access,read_stream,publish_stream,user_photos' });
}
A button click fires facebookLogin() which logs in a facebook user, getting a facebook session that includes an access token, which I JSON serialize and post to the server. The server then saves this access token to the database table FacebookDeliveryQueue.
I have a Windows service running that periodically queries the FacebookDeliveryQueue table and attempts to post on a user's wall using the access token we saved earlier:
IQueryable<FacebookDeliveryQueue> toSend = objectContext.FacebookDeliveryQueues.Where(p => !p.IsDelivered);
foreach (FacebookDeliveryQueue facebookDeliveryQueueItem in toSend)
{
string facebookAccessToken = facebookDeliveryQueueItem.Cart.FacebookAccessToken;
string facebookRecipientId = facebookDeliveryQueueItem.Cart.FacebookRecipientId;
var client = new FacebookClient(facebookAccessToken);
dynamic parameters = new ExpandoObject();
parameters.message = facebookDeliveryQueueItem.Cart.CustomMessageBody;
client.Post(facebookRecipientId + "/feed", parameters);
}
My problem is, this ONLY works with access tokens from the user that created the facebook application. E.g.
Success:
I, the creator of this application, log in and pick one of my friends to send a message to, this info is saved to the database, the service runs, my message is posted to my friend's wall.
Failure:
I log in on my dummy test account (approving the app permissions on this account), pick one of my dummy test account's friend, this info is saved to the database, the service runs and throws an invalid access token error.
Any ideas why?
Update: Switched to Oauth login -- no change. Still getting "(OAuthException) Invalid access token signature." when attempting to post to friend's wall.
Looks like you're using facebook's old login methods, which they recently just turned off, so your old access tokens aren't valid anymore? And your javascript isn't generating the right kind of token. Read the latest version of the FB.login documentation for more info on what changes you need to make. Specifically,
pass oauth: true to the FB.init call
check for response.authResponse instead of response.session now.
Also, check that your app isn't in "sandbox mode". Go to the app settings page and click on "advanced". Sandbox mode makes it so that only developers can use the app.
The persistence to the database was silently trimming the access token to 75 characters, which in the case of my own user, was enough (small user id because it's an old account) -- but five characters too short in the case of my test account which has a very large user id.
Woops.