ASP.net: Getting HTTPS data server-side? - asp.net

I previously asked on StackOverflow how to parse XML downloaded programmatically by my ASP.net application. By this, I mean that the user visits https://www.example.com/page1.aspx. The code-behind for page1.aspx is supposed to somehow download and parse an xml file located at https://www.example.com/foo.xml.
I received good answers about how to parse the XML. However, I've been out of luck with being able to retrieve XML from my secure HTTPS server.
I am looking at a situation where https://www.example.com/foo.xml authenticates requests with a cookie. (third party system, not Forms Authentication). The answer I received to my question about how to download and parse XML suggested that I use the System.Net.WebClient class. I read that the WebClient class must be customized to work with cookies. Therefore, I wrote the following code:
public class WebClientWithCookies : WebClient
{
private CookieContainer m_container = new CookieContainer();
public CookieContainer CookieContainer
{
get { return m_container; }
set { m_container = value; }
}
public void addCookie(Cookie cookie)
{
m_container.Add(cookie);
}
protected override WebRequest GetWebRequest(Uri address)
{
WebRequest request = base.GetWebRequest(address);
if ( request is HttpWebRequest)
{
(request as HttpWebRequest).CookieContainer = m_container;
}
return request;
}
} // end class
However, when the request is received at https://www.example.com/foo.xml, there are no cookies in the request, and so it doesn't work.
How can I work around this problem?

Where are you creating the cookie? That seems to be a missing part from the code you are displaying. There is an "HttpCookie" class as part of the System.Web name space that may be useful.

Here's the code that I eventually wrote that solved the problem:
private XmlDocument getXmlData(string url)
{
System.Net.HttpWebRequest rq = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url);
System.Net.CookieContainer container = new System.Net.CookieContainer();
for (int i = 0; i < System.Web.HttpContext.Current.Request.Cookies.Count; i++)
{
System.Web.HttpCookie httpcookie = System.Web.HttpContext.Current.Request.Cookies[i];
string name = httpcookie.Name;
string value = httpcookie.Value;
string path = httpcookie.Path;
string domain = "my.domain";
System.Net.Cookie cookie = new System.Net.Cookie(name, value, path, domain);
container.Add(cookie);
}
rq.CookieContainer = container;
rq.Timeout = 10000;
rq.UserAgent = "Asset Tracker Server Side Code";
System.Net.HttpWebResponse rs = (System.Net.HttpWebResponse)rq.GetResponse();
System.Text.Encoding enc = System.Text.Encoding.GetEncoding(1252);
System.IO.StreamReader reader = new System.IO.StreamReader(rs.GetResponseStream());
System.Xml.XmlDocument xml = new System.Xml.XmlDocument();
xml.Load(rs.GetResponseStream());
return xml;
}

Related

How to pass array to php url from c#? [duplicate]

Is it possible to pass parameters with an HTTP get request? If so, how should I then do it? I have found an HTTP post requst (link). In that example the string postData is sent to a webserver. I would like to do the same using get instead. Google found this example on HTTP get here. However no parameters are sent to the web server.
My preferred way is this. It handles the escaping and parsing for you.
WebClient webClient = new WebClient();
webClient.QueryString.Add("param1", "value1");
webClient.QueryString.Add("param2", "value2");
string result = webClient.DownloadString("http://theurl.com");
First WebClient is easier to use; GET arguments are specified on the query-string - the only trick is to remember to escape any values:
string address = string.Format(
"http://foobar/somepage?arg1={0}&arg2={1}",
Uri.EscapeDataString("escape me"),
Uri.EscapeDataString("& me !!"));
string text;
using (WebClient client = new WebClient())
{
text = client.DownloadString(address);
}
In a GET request, you pass parameters as part of the query string.
string url = "http://somesite.com?var=12345";
The WebRequest object seems like too much work for me. I prefer to use the WebClient control.
To use this function you just need to create two NameValueCollections holding your parameters and request headers.
Consider the following function:
private static string DoGET(string URL,NameValueCollection QueryStringParameters = null, NameValueCollection RequestHeaders = null)
{
string ResponseText = null;
using (WebClient client = new WebClient())
{
try
{
if (RequestHeaders != null)
{
if (RequestHeaders.Count > 0)
{
foreach (string header in RequestHeaders.AllKeys)
client.Headers.Add(header, RequestHeaders[header]);
}
}
if (QueryStringParameters != null)
{
if (QueryStringParameters.Count > 0)
{
foreach (string parm in QueryStringParameters.AllKeys)
client.QueryString.Add(parm, QueryStringParameters[parm]);
}
}
byte[] ResponseBytes = client.DownloadData(URL);
ResponseText = Encoding.UTF8.GetString(ResponseBytes);
}
catch (WebException exception)
{
if (exception.Response != null)
{
var responseStream = exception.Response.GetResponseStream();
if (responseStream != null)
{
using (var reader = new StreamReader(responseStream))
{
Response.Write(reader.ReadToEnd());
}
}
}
}
}
return ResponseText;
}
Add your querystring parameters (if required) as a NameValueCollection like so.
NameValueCollection QueryStringParameters = new NameValueCollection();
QueryStringParameters.Add("id", "123");
QueryStringParameters.Add("category", "A");
Add your http headers (if required) as a NameValueCollection like so.
NameValueCollection RequestHttpHeaders = new NameValueCollection();
RequestHttpHeaders.Add("Authorization", "Basic bGF3c2912XBANzg5ITppc2ltCzEF");
GET request with multiple params:
curl --request GET --url
http://localhost:8080/todos/?limit=10&offset=2 --header
'content-type:application/json'
You can also pass value directly via URL.
If you want to call method
public static void calling(string name){....}
then you should call usingHttpWebRequest webrequest = (HttpWebRequest)WebRequest.Create("http://localhost:****/Report/calling?name=Priya);
webrequest.Method = "GET";
webrequest.ContentType = "application/text";
Just make sure you are using ?Object = value in URL

Unable to rectify VeraCode CWE ID 918 - (SSRF) in ASP.NET

Long story short, no matter what I try VeraCode continues to flag 8 lines of my code as flaws with CWE 918. This is old code so I'm not sure why it's suddenly being flagged.
Here's an example [offending] method with the flagged line in bold
public virtual async Task<HttpResponseMessage> Put(string controller = "", Dictionary<string, object> parameters = null, object body = null)
{
if (string.IsNullOrWhiteSpace(ApiBaseUrl)) return null;
HttpResponseMessage response = null;
using (var client = GetHttpClient())
{
client.BaseAddress = new Uri(ApiBaseUrl);
if (!string.IsNullOrEmpty(Token)) client.DefaultRequestHeaders.Add("Token-Key", Token);
if (!string.IsNullOrEmpty(DeviceId)) client.DefaultRequestHeaders.Add("DeviceId", DeviceId);
var url = GenerateUrl(controller, parameters);
var requestBody = GeneratedHttpContent(body);
if (requestBody == null) requestBody = new StringContent("");
**response = await client.PutAsync(url, requestBody);**
await LogError(response);
return response;
}
}
Here's my proposed fix that utilized an extension method to validate the URL
var url = GenerateUrl(controller, parameters);
var requestBody = GeneratedHttpContent(body);
if (requestBody == null) requestBody = new StringContent("");
**if (url.IsValidUrl())
{
response = await client.PutAsync(url, requestBody);
}
else
{
response = new HttpResponseMessage(HttpStatusCode.BadRequest);
}**
await LogError(response);
return response;
Here is the extension method with a VeraCode attribute
[RedirectUrlCleanser]
public static bool IsValidUrl(this string source)
{
return Uri.TryCreate(source, UriKind.RelativeOrAbsolute, out Uri uriResult) && Uri.IsWellFormedUriString(source, UriKind.RelativeOrAbsolute);
}
I can have VeraCode automatically mitigate based on the attribute, but our client will be performing their own scan and certainly won't have that setting enabled.
Any ideas on how I can resolve this would be appreciated.
The true source of the flaw is inside of your GenerateUrl method which is unfortunately not shown, but here is the general idea of what the Veracode is complaining about.
For CWE ID 918 it is hard to make Veracode recognize your fix unless you have static URL. You need to validate all your inputs that become parts of your request URL.
Below is what I found at the Veracode site:
https://community.veracode.com/s/question/0D52T00004i1UiSSAU/how-to-fix-cwe-918-veracode-flaw-on-webrequest-getresponce-method
The complete solution existed only for the case where you have single or some small number of possible input values (white list):
public WebResponse ProxyImage(string image_host, string image_path)
{
string validated_image_host = AllowedHosts.Host1;
if (image_host.Equals(AllowedHosts.Host2))
validated_image_host = AllowedHosts.Host2;
string validated_image = AllowedImages.Image1;
if (image_path.Equals(AllowedImages.Image2))
validated_image = AllowedImages.Image2;
string url = $"http://{validated_image_host}.example.com/{validated_image}";
return WebRequest.Create(url).GetResponse();
}
If the set of possible valid values is too large for that kind of validation then you need to fix the flaw by implementing dynamic validation of inputs using regular expressions. Unfortunately, Veracode is not smart enough to recognize that kind of fix, so "mitigation by design" is still required.
public WebResponse ProxyImage(string image_host, string image_path)
{
var image_host_regex = new System.Text.RegularExpressions.Regex("^[a-z]{1,10}$");
if (!image_host_regex.Match(image_host).Success)
throw new ArgumentException("Invalid image_host");
var image_path_regex = new System.Text.RegularExpressions.Regex("^/[a-z]{1,10}/[a-z]{1,255}.png$");
if (!image_path_regex.Match(image_path).Success)
throw new ArgumentException("Invalid image_host");
string url = $"http://{image_host}.example.com/{image_path}";
return WebRequest.Create(url).GetResponse();
}
Another way to fix this issue (which is kind of a hack) is to append your query string parameters in the baseAddress of the HttpClient, this way the veracode will not treat it like a flaw.
Here is how the solution would look like
public async Task<Data> GetData(string input)
{
try
{
var httpClient = new HttpClient();
//Appended the parameter in base address to
//to fix veracode flaw issue
httpClient.BaseAddress = new Uri($"https://someurl.com/somefunction/{input}");
//passing empty string in GetStringAsync to make sure
//veracode doesn't treat it like modifying url
var content = await httpClient.GetStringAsync("");
return JsonConvert.DeserializeObject<Data>(content);
}
}

Post comment to facebook wall using asp.net

I have a website that I have registered as a facebook app - I now have an app ID.
My website is ASP.net C#. When the user clicks a button I'd like it to post a pre-defined message to their wall. I'm expecting Facebook to present a login dialog to the user - they login and grant publish permission to for my website app.
Does anyone have any sample code that would do this? I think I need to use the graph API but all the examples I've seen use PHP - which I know nothing about. I'm looking for an example that would use Java Script (of which I know almost nothing) or C# (beautiful!).
* Update *
I have managed to get the access_token. Now I make a call through the Facebook C# API to post to the wall. I get the error message:
(#803) Some of the aliases you requested do not exist: profile_id
I've stepped through the api code and found that it is trying to post to the following address: {https://graph.facebook.com/PROFILE_ID/feed}, the post data is: message=Sample+message+from+c%23+sdk&access_token=199209316768200|2.1avFTZuDGR4HJ7jPFeaO3Q__.3600.1302897600.1-100000242760733|R4DkNDf4JCb6B2F64n5TSQwBqvM
I'm pretty sure my token should be valid. Prior to requesting access token I requested publish_stream on the app authorization request as follows:
Response.Redirect ("https://www.facebook.com/dialog/oauth?client_id=" + myAppId + "&redirect_uri=" + myURL + "&scope=publish_stream");
The sdk code that actually makes the request is as follows:
private string MakeRequest(Uri url, HttpVerb httpVerb,
Dictionary<string, string> args)
{
if (args != null && args.Keys.Count > 0 && httpVerb == HttpVerb.GET)
{
url = new Uri(url.ToString() + EncodeDictionary(args, true));
}
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
request.Method = httpVerb.ToString();
if (httpVerb == HttpVerb.POST)
{
string postData = EncodeDictionary(args, false);
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] postDataBytes = encoding.GetBytes(postData);
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = postDataBytes.Length;
Stream requestStream = request.GetRequestStream();
requestStream.Write(postDataBytes, 0, postDataBytes.Length);
requestStream.Close();
}
try
{
using (HttpWebResponse response
= request.GetResponse() as HttpWebResponse)
{
StreamReader reader
= new StreamReader(response.GetResponseStream());
return reader.ReadToEnd();
}
}
Can anyone see what I'm doing wrong?
Many thanks,
Rob.
First of all, you need to take care of Authentication. You need to create an Application, and use OAuth to get hold of the access token. It's all described in the Authentication guide.
To post something to the user's wall, take a look at the Graph API under Publishing.
As a start, you could use Facebook's C# SDK
You could look to use a .NET library like http://facebooknet.codeplex.com/ to do this. There are a couple out there, I just remembered this one...
HTH.
I created a video showing how to do this using OG: http://www.markhagan.me/Samples/Grant-Access-And-Post-As-Facebook-User-ASPNet
In case you don't have time to watch the video, here is the full code:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Facebook;
namespace FBO
{
public partial class facebooksync : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
CheckAuthorization();
}
private void CheckAuthorization()
{
string app_id = "374961455917802";
string app_secret = "9153b340ee604f7917fd57c7ab08b3fa";
string scope = "publish_stream,manage_pages";
if (Request["code"] == null)
{
Response.Redirect(string.Format(
"https://graph.facebook.com/oauth/authorize?client_id={0}&redirect_uri={1}&scope={2}",
app_id, Request.Url.AbsoluteUri, scope));
}
else
{
Dictionary<string, string> tokens = new Dictionary<string, string>();
string url = string.Format("https://graph.facebook.com/oauth/access_token?client_id={0}&redirect_uri={1}&scope={2}&code={3}&client_secret={4}",
app_id, Request.Url.AbsoluteUri, scope, Request["code"].ToString(), app_secret);
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
StreamReader reader = new StreamReader(response.GetResponseStream());
string vals = reader.ReadToEnd();
foreach (string token in vals.Split('&'))
{
//meh.aspx?token1=steve&token2=jake&...
tokens.Add(token.Substring(0, token.IndexOf("=")),
token.Substring(token.IndexOf("=") + 1, token.Length - token.IndexOf("=") - 1));
}
}
string access_token = tokens["access_token"];
var client = new FacebookClient(access_token);
client.Post("/me/feed", new { message = "markhagan.me video tutorial" });
}
}
}
}
I am using this http://facebooksdk.codeplex.com/ . I am using the latest stable release, easy to use. To comment, just post with /OBJECT_ID/comments for more, refer http://developers.facebook.com/docs/reference/api/#publishing and http://developers.facebook.com/docs/reference/api/post/
How about trying this API tha I recently developed to make integrating with Facebook easier.
Here is a code sample for you there's more documentation on the site.
Authenticating Users
Imports Branches.FBAPI
...
Dim SI As New SessionInfo("[application_id]","applicaiton_secret")
'Redirects user to facebooks
SI.AuthenticateUser("http://[my url]", New SessionInfo.PermissionsEnum(){SessionInfo.PermissionsEnum.email, SessionInfo.PermissionsEnum.read_stream}))
'Called when the user is returned to your page
Dim FSR = FS.ReadFacebooAuthResponse
Response.Write(FSR.Access_Token)
Response.Write(FSR.UserID)
Making Posts
Imports Branches.FBAPI
...
Dim SI As New SessionInfo("[access_token]"))
Dim Posts = New Functions.Posts(SI)
Dim P As New Post
P.name = "name of post"
P.message = "message"
P.link = "www.cnn.com"
P.caption = "my caption"
Posts.PublishCreate("[object ID to post to]", P)
Dim PostID = P.id
Getting stuff from the graph.
Dim SI As New SessionInfo("[access_token]"))
Dim Req New Functions.Requests(SI)
Dim User = Req.GetUserInfo("[optional user ID]")
Response.Write(U.name)

How can I read in C# XML from another page while logged in to the site

I have logged in to the site with my webbrowser and whenever I try to call
WebClient myWebClient = new WebClient();
string str = myWebClient.DownloadString("http://localhost/myxml.aspx");
Response.Write(str.ToString());
Or
XmlTextReader reader = new XmlTextReader(url);
while (reader.Read()) {
Response.Write(reader.ReadOuterXml());
}
Response.Write returns me the login page.
Is there away to attach user SessionId to WebClient or XmlTextReader or how can I request another page in C# with current logged user?
You'll need to use an object that can handle storing cookies. In this case, you'll need the HttpWebRequest class. You'll also need a CookieContainer to manage authentication cookies.
To do this you would:
Create a CookieContainer object (a cookie jar) that you can keep track of throughout the scope of every request you make.
Create an HttpWebRequest that logs into the site you're accessing.
Use the CookieContainer you created in step 1 for every subsequent request.
Below is an example of how to use the HttpWebRequest, HttpWebResponse, and CookieContainer classes together to make a simple request that will set some cookies, and then using those cookies on a subsequent request. The rest should be easy assuming everything is well formed markup ;)
CookieContainer cookieJar = new CookieContainer();
var webRequest = (HttpWebRequest)HttpWebRequest.Create("http://www.google.com");
webRequest.CookieContainer = cookieJar;
var webResponse = webRequest.GetResponse();
using (var reader = new StreamReader(webResponse.GetResponseStream()))
{
Response.Write(reader.ReadToEnd());
}
var anotherWebRequest = (HttpWebRequest)HttpWebRequest.Create("http://www.google.com/search?q=stackoverflow.com");
anotherWebRequest.CookieContainer = cookieJar;
webResponse = anotherWebRequest.GetResponse();
Another option (if you really want to use the WebClient class) would be to parse out the ResponseHeaders property of the class once you've made your request and include the appropriate cookies in your next request. This is a little more involved though since it requires you to manage your cookies manually.
Since I'm assuming that you want to be able to traverse your web responses as XML, I suggest you look into the open source library, HtmlAgilityPack. It allows you to send in markup from a web site that is (most likely) not well-formed, or has some sort of invalid markup in it, and then fixes the invalid parts so that you can traverse it like XML.
While doing some screen scraping, I had the same issue. I was requesting a Classic ASP app on an IIS server (I could tell by some of the headers that the server reponded with). The way I supported an ongoing session was by enabling Cookies on the WebClient. Theres no toggle for it, you have to subclass WebClient to get it to work.
public class CookieAwareWebClient : WebClient
{
protected CookieContainer _container = new CookieContainer();
public CookieContainer Cookies
{
get { return _container; }
set { _container = value; }
}
protected override WebRequest GetWebRequest(Uri address)
{
HttpWebRequest httpRequest = base.GetWebRequest(address) as HttpWebRequest;
if (httpRequest.CookieContainer != null)
{
if (httpRequest != null)
{
CookieCollection newCookies =
GetUniqueCookies(
address
,httpRequest.CookieContainer.GetCookies(address)
);
foreach (Cookie c in newCookies)
httpRequest.CookieContainer.Add(c);
}
}
else
httpRequest.CookieContainer = this.Cookies;
return (WebRequest)httpRequest;
}
Note: this isn't a unique solution, I found this out there on the web myself, but I've implemented the solution and it works really well.

How to submit a form automatically using HttpWebResponse

I am looking for an application that can do the following
a) Programmatically auto login to a page(login.asxp) using HttpWebResponse by using already specified username and password.
b) Detect the redirect URL if the login is successful.
c) Submit another form (settings.aspx) to update certain fields in the database.
The required coding needs to be using asp.net
The application needs to complete this entire process in the same session cookie.
string sUrl = "login.aspx";
HttpWebRequest oRequest = (HttpWebRequest)WebRequest.Create(sUrl);
CookieContainer oMyCookies = new CookieContainer();
oRequest.CookieContainer = oMyCookies;
// encode postdata into byte array. the postdata string format will most likely be different and you'll have to examine the postdata going back and forth using some firefox addon like LiveHTTPHeaders
byte[] oPostData = System.Encoding.UTF8.GetBytes("username=" + HttpUtility.UrlEncode(sUser) + "&pass=" HttpUtility.UrlEncode(sPass));
using (Stream oStream = oRequest.GetRequestStream())
{
oStream.Write(oPostData, 0, oPostData.Length);
}
HttpWebResponse oResponse = oRequest.GetResponse();
// save response cookies in our cookie object for future sessions!
foreach (Cookie oCookie in oResponse.Cookies)
{
oMyCookies.SetCookies(sUrl, oCookie.ToString());
}
// maybe check response headers for location
string sResponseContents = null;
using (StreamReader oReader = new StreamReader(oResponse.GetResponseStream())
{
// store server response into string
sResponseContents = oReader.ReadToEnd();
}
...this is the basic code required for what you want to do.

Resources