Reflected Cross-Site Scripting in SharePoint Search Box Web Part - sharepoint-2013

While a third party company executing a security assessment on our SharePoint 2013 project. The Security Assessment was comprised of a Vulnerability Assessment. The Cycura determined that the "Search Box Web Part" functionality is vulnerable to XSS attacks.
The Proof of Concept came up like below:
Vulnerable parameter: "k":"String"
Payload: "test"><a onmouseover="alert('xss')">xxx
GET /Pages/SearchResults.aspx?k=test"><a onmouseover="alert('xss')">xxx HTTP/1.1 Host: wwwqa.xyz.com
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:53.0) Gecko/20100101 Firefox/53.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Cookie: _ga=GA1.3.911615250.1492781812; dtLatC=31; dtPC=256094571_636h3; WSS_FullScreenMode=false; SearchSession=4d21f382%2D23e3%2D4f86%2D91ad%2Dc6c712e70704;
_gat_UA-82498113-1=1; dtCookie=911302E10B144FAA0C644F92C2950F93|UUErZUN1c3RvbWVyfDE
Connection: close
Upgrade-Insecure-Requests:
1enter image description here
The recommendations was to perform sanitization and input validation on user supplied data. the steps of validation, sanitization and escaping should happen both in client and server side. Whenever possible.
Did anyone had the same security assessment issue and if anyone managed to resolve or get an idea how to manage that since this is using SP OOTB search box web parts.
Much appreciate your help and contributions.

XSS can be prevented by defining white-list of acceptable charaters in user input. The key to prevent this attack is never trust user data. Always sanitize the user input. Always perform data validation i.e whether it has some blacklist characters[character which should not be allowed to user input] on input output both. https://www.owasp.org/index.php/Data_Validation.
This link will help you to understand data sanitazation,validation.
https://www.troyhunt.com/understanding-xss-input-sanitisation/
Here is the prevention cheat sheet for XSS. https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet.
https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet

Related

Sampler fails due to regex value conflict

I am trying to write a test script in Jmeter the script works fine for a single user, but the same script fails for multiple users, the issue is there are 2 regex one is extracting the authentication details and the other is extracting the jobs associated to each user, now in some of the samplers when I am running the script for more than 2 users it picks the job of one user and the authentication details from another due to this the server sends the 500 error message,
Here's the data that authKey is capturing
sitecode: 601584
credential: {"SiteCode":601584,"UserName":"ADMIN","FirstName":"ADMIN","LastName":"ADMIN","RoleId":1,"UserTypeId":1,"SiteId":696,"StaffId":0,"UserId":15240,"AuthKey":"1548dbe78e5d4a71bbe8a70112c66eb82899c6d38dd140be91b7cf5610b140617ed460d6ba674d3089c7199941e1342b","DefaultPagePath":"","UserEntity":2519,"TypeOfEntity":20,"Culture":null,"SuperFranchiseId":0,"SuperFranchiseName":null,"MasterFranchiseId":null,"FranchiseIds":null,"CountryList":[],"MarketId":0,"MarketName":null,"TechnicianId":0,"Actions":"","GroupId":10,"SessionId":103807374,"EntityRef":2519,"IsLocked":false,"EncryptedAuthKey":"tNKvRhDrm4R99OCP45Q+uQnSa+CLfm2iLuTG9lCCWo17CRXPGoCzrzj2nQ0nC68IrqkP6ygRH0hQrrdosqmXoYngBxu04l4zH7rNhMZ1bbcK49QKBVQ9sVp3mTUPjzaBU1MH431lTyGCQMfCJafHHxY+XJNSMeTk/CG6m6D47oZW/v0az17IYcNL586QC6Vsm5BGul5U6+c71fSnTQfIdiWY5Ijye2xjDTHN1LZ8u9UGtrShF7zFCm2hkdFsQ2pk"}
Content-Type: application/json
sec-ch-ua: "Google Chrome";v="89", "Chromium";v="89", ";Not A Brand";v="99"
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36
Content-Length: 3519
Host: qa-coreservices.wsautovhc.co.uk
The site code goes as 601584
Here's the value of VHC that's been picked it's from a different site user
POST https://qa-coreservices.wsautovhc.co.uk/api/vhc/v2/update
POST data:
{"IsTCO":true,"TCOId":1016590096,"TimeIn":"00:00:00","TimeOut":"00:00:00","CustomerBookedWork":"","CustomerStatus":"","WorkStatus":"","MobilityStatus":"","RepeatRepair":"false","DateIn":"","DateOut":"","SquashedFrogModelId":0,"SquashedFrogurl":null,"TotalPhotoCount":0,"IsMoveVHC":false,"LinkGuid":"00000000-0000-0000-0000-000000000000","CustomerName":null,"TechnicianName":null,"TemplateLogoAssetId":0,"TemplateLogoUrl":null,"SAName":null,"CustomerUUId":null,"SiteName":null,"SAFirstName":null,"SASurName":null,"SADisplayName":null,"CustomerFirstName":null,"CustomerSurName":null,"CustomerSalutation":null,"CustomerEmail":null,"CustomerMobile":null,"DialingCode":null,"RoleID":0,"SAEmail":null,"MitchellIntegration":null,"VhcTotalId":0,"VhcTotalData":{"Notes":null,"OnlineAuthAuthorisationDate":null,"FuelGaugeValue":0,"EmacIntegrationInfo":null,"DmsMetaData":null,"Chat":null,"NotApplicableTemplateItemTypeIds":null,"UberVhcScoreCard":null,"OnlinePayments":null,"IsCreateRepairOrder":false,"IsGetRepairOrder":false,"EngineNumber":"","PartsPartiallyPriced":false,"LabourPartiallyPriced":false,"PartiallyChecked":null,"ParentCode":null,"IsTransmittedToDms":false,"YearOfMake":"","ChatStages":0,"RequestCustomerCallBack":false,"WhatsApp":null},"VQCQuestionIds":null,"VQCByUserId":0,"TotalVideoCount":0,"SquashedfrogPhotoCount":0,"SquashedfrogVideoCount":0,"HasIntegrationRequired":false,"IsAutoSendMessage":false,"PreviousVhcComments":null,"ConvertToVideoCheck":false,"VhcJcbLookup":null,"VhcJcbTemplateLookupId":0,"IsAppRequest":false,"NissanRecallInfo":null,"HondaRecallInfo":null,"VisitReasons":[],"TemplateName":null,"QualityControlName":null,"SAStartTStamp":null,"BoatMetaData":{"BoatName":"","EngineId1":"","EngineId2":"","TransmissionId":"","BoatLength":0},"EventsMetaData":null,"Workshop":"Select","DateAdded":"24/05/2021 11:38:40","DateChecked":"","DateParts":"","DateLabour":"","DateAuthorised":"","Status":"N","VHCId":1012875189,"CustomerId":1004437412,"VHCDate":"20210524","Make":"2019","Model":"124 SPIDER","RegNo":"REG55671","Mileage":1280,"JobCardNo":"JC5461","ItemNo":"","FollowUpDate":"20210524","Technician":0,"AuthTotal":0.0,"IdentTotal":0.0,"InvTotal":0.00,"QualityControl":0,"RepairOrderNo":"","Deleted":false,"SiteCode":601470,"TimeStamp":"24/05/2021 11:38:40","Altered":false,"ServiceAdvisor":0,"DateWorkIssued":"","DatePartsIssued":"","VIN":"","TemplateId":47692,"Populated":false,"FranchiseId":27,"AuthTotalIncVAT":0.0,"IdentTotalIncVAT":0.0,"LastAccessTStamp":null,"LastAccessUser":0,"StartTStamp":null,"TyresRequired":false,"MultiRole":false,"CommentsAvailable":false,"MultiRoleSAId":0,"MultiRoleTStamp":null,"FirstRegistrationDate":"","NextMOTDate":"","NextServiceDate":"","DefaultServiceRate":0.00,"AgreedEstimate":0.0,"WorkRequired":"","AverageMileagePerAnnum":"0","PushedToDMS":false,"TransmittedToFord":false,"OriginalVHCDate":"20210524","MileageUnit":"m","PreviousVHCId":0,"PreviousVHCDate":"","PricedByUserId":0,"Revisit":0,"HasBeenLate":false,"FirstEvent":false,"RevisitRecorded":false,"UnknownReasonCode":false,"DMSAccountCode":"","JobType":0,"PhotoCount":0,"VideoCount":0,"NextCheckTachographDate":"","NextChangeCoolantDate":"","NextChangeBrakeFluidDate":"","LastWorkshopVisitDate":"","MileageLastWorkshopVisit":0,"LastServiceDate":"","MileageLastService":0,"ServiceCode":"","EngineOil":"","TransmissionOil":"","PositionNumber":0,"AxleNumber":0,"AxleLocation":"","FirstTyreLocation":"","SecondTyreLocation":"","VHCIcon":null,"FastLaneVHC":0,"Pin":null,"VhcType":0,"EngineNumber":""};
[no cookies]
The site code here is different than the one that's captured in the AuthKey and this creating the problem.
What am I doing wrong?
it picks the job of one user and the authentication details from another
it cannot happen, as per JMeter Documentation
Properties are not the same as variables. Variables are local to a thread; properties are common to all threads, and need to be referenced using the __P or __property function.
So if one user extracts some value from the response another user cannot access this value (unless you convert it into a JMeter Property using __setProperty() function) so most probably the error is either in your extraction logic or in business logic of your test scenario. See article on Thread-local storage for more information if needed.
So inspect responses and extracted values using Debug Sampler and View Results Tree listener combination, hopefully you will be able to detect the inconsistency yourself.
Also JSON doesn't seem to be a regular language so parsing it using regular expressions is not the best idea, maybe it worth consider using JSON Extractor or even better JSON JMESPath Extractor instead?

Access token and ID token storage for serverless app

I'm writing a serverless app with AWS (Lambda, API Gateway, Cognito, etc) and I find myself wondering how to best secure my stack.
I've read that for applications using a server, EC2 or otherwise, best practice is to keep user's ID tokens stored on the backend. This makes sense, since a node process would provide me a long term solution for hanging onto and reusing ID tokens. A serverless app on the other hand, does not provide this luxury. I've considered just keeping it on the front end- since after all, JWT tokens provided by cognito are signed, and should therefore be tamper proof, but this seems a bit unsettling from my end. I'd much prefer a system where users have no direct access to their own tokens. I've also thought about just requesting a new token for every request sent to Lambda, but this too seems like a far from perfect solution.
Is there some kind of accepted best practice surrounding serverless authentication and authorization? Am I on the right track just storing my tokens client side while the user has the app open?
I don't see an issue storing your tokens client side. The user can copy paste the token from the header request anytime. The token is not a secret. It can't be tampered because it's digitally signed.
For example bellow are the headers of a request.
In Authorization is stored the jwt token that can be decoded in https://jwt.io/
but it cannot be modified,
Host: aa.aa.aa
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:66.0) Gecko/20100101 Firefox/66.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer: token234567890-eddedede
X-Requested-With: XMLHttpRequest
Connection: keep-alive
In addition, it’s best practice to expire yr tokens and renew at certain intervals.

Error 401 on WEB API 2 when there is lot of request from Android device

I’m developing an Android App and a Web Service that communicate. My Web Service is in WEB API 2 with token bearer authentication.
My problem is that when I send too many requests (~20 request in 15 seconds) to my Web Service from my Android App, the WS response with
“401” : “Authorization has been denied for this request”
This happen ONLY on the production server (Amen hoster) AND from the Android Device. For example, if I try with Postman, everything works fine. So it’s related to my production server and/or my android app request.
The code for access to the Web Service
URL obj = new URL(SERVEUR_URL + url);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("Authorization", "Bearer " + token);
con.setRequestProperty("Content-Type", "application/json");
int responseCode = con.getResponseCode();
String responseMessage = con.getResponseMessage();
The authentication provider on my Web Service is the default one. No modifications.
The request from my Android App (not work every time)
GET http://api.xxxx.com/api/Weesps/GetAvailableWeesps HTTP/1.1
Authorization: Bearer XXXX
Content-Type: application/json
User-Agent: Dalvik/2.1.0 (Linux; U; Android 6.0; Google Nexus 5X - 6.0.0 - API 23 - 1080x1920 Build/MRA58K)
Host: api.xxxx.com
Connection: Keep-Alive
Accept-Encoding: gzip
The request from Postman (work every time)
GET http://api.xxxx.com/api/Weesps/GetAvailableWeesps HTTP/1.1
Host: api.xxxx.com
Connection: keep-alive
Authorization: Bearer XXXX
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36
Postman-Token: bca55154-775d-9709-7a8b-4793393890ad
Accept: */*
Accept-Encoding: gzip, deflate, sdch
Accept-Language: fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4
Cookie: dadaproaffinity=14ff51cc869a14d3552485cb4ceee1faa1be7165cc5d4b0e2b19370f11afcbea
What I have tried:
Reproduce this error in local : it works fine on local server (web and SQL servers) from android app or from Postman
I check that the token was sent correctly in every requests
The request from Android is the same every time
Tried to add missing header to my android app request
I spend two days on this problem and read many stackoverflow posts but no one helps me.
Thanks for your help.
UPDATE 1 :
With Fiddler I saw that in GET request from Postman, they were a Cookie header. This cookie is sent when we ask for a bearer token.
Example of token response from the server
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 691
Content-Type: application/json;charset=UTF-8
Expires: -1
Server: Microsoft-IIS/8.5
Set-Cookie: .AspNet.Cookies=XXXX; path=/; HttpOnly
X-Powered-By: ASP.NET
X-Powered-By: ARR/2.5
Date: Tue, 31 May 2016 16:55:39 GMT
{"access_token":"XXXX","token_type":"bearer","expires_in":1209599,"userName":"Foo",".issued":"Tue, 31 May 2016 16:55:40 GMT",".expires":"Tue, 14 Jun 2016 16:55:40 GMT"}
Fiddler and Postman saved this cookie and they automatically put it in requests to API (example on the “The request from Postman” code block). When I remove the cookie from the Postman GET request, it doesn’t work (just like my android app).
Now, the question is: why WEB API 2 send a cookie instead of only using the token ? And why the token work great in the first requests and don’t work properly for the following requests ?
According to ASP.NET WebAPI2 flow you can see on the bottom of that page, it seems your requests are always authenticated but sometimes fail to get authorized.
So imo, the AuthorizationFilter[Authorize] rejects some of your requests for an unknown reason. What I would suggest is to dump the request your API receives as well as the claims identity attached to the token. Try to see if there is differences between them when you have a successful response and when you have a 401.
That way, you may be able to determine either it is your request that got malformed, if it is the claims identity that is not good or if it is the AuthorizationFilter that refuses you for another reason (like too much queries or else).
Good luck !
UPDATE 1
According to your new input, I think that your Web API is configured to use both token and cookie authentication.
What I see here is you have two solutions :
1°/ Store the returned cookie in your Android application and use it for next calls. Simplest and fastest way to solve your problem without changing all your API, but you store an authorization cookie : it can leads to security problem (CSRF attacks).
2°/ You can check how your authentication and authorization filters are set to disable cookie authentication and only rely on token authentication : it will hence forces all the requests and your API to only use token and will prevents you from suffering CSRF attacks. More complex because you have to dig into your web API configuration.
Check the following links (sorry, as I don't have enough reputation yet to post more than 2 links per post, you'll find them as text at the end of my answer) :
ASP.net Secure a Web API 2.2[2] : From the chapter "Configuring the Authorization Server" at the bottom
MSDN article on Web API security[3] : More general and technical information about web api security, how to secure it and CRSF attacks
StackOverflow .NET cookie and token authentication[4] : Check David Banister's answer, I think it is exactly what you want to do : Only use token for all your API calls.
StackOverflow Authorize filter and authentication[5] : More information about such mechanisms for your API
And finally
Cookie authentication with web API and 401 codes[6] : Sounds like your actual problem, isn't it ?
I hope it helps you, good luck !
// Links
2: www.asp.net/web-api/overview/security/individual-accounts-in-web-api
3: msdn.microsoft.com/en-us/magazine/dn201748.aspx
4: stackoverflow.com/questions/22568409/mvc-net-cookie-authenticated-system-acessing-a-web-api-with-token-authenticatio
5: stackoverflow.com/questions/21231751/authorize-filter-and-authentication
6: brockallen.com/2013/10/27/using-cookie-authentication-middleware-with-web-api-and-401-response-codes/
Finally, I got my answer:
My Web Service send a Cookie named “dadaproaffinity” the first time I ask for a request. This Cookie was automatically put on the following request by Postman but not by Android HttpUrlConnection. So, I just take this Cookie and now I just add this Cookie on every requests with the Token.
But : This cookie is send by IIS, not by my Web Service ! That’s why it works on local but not on the production server. I googled this cookie and there are very few responses about that. The only one that I find in English is :
Technical Cookie of IIS Server hosting the site.
Need to route to the correct server session, in order to keep it active
Does anyone have more information about this IIS Cookie ?

RegEx to Atlassian Jira Token Finder

I'm using Jmeter to test my Jira instance. I recorded a login and a Scrumboard action.
When I want to replicate this using 2000 users I am getting an error.
I know this is because of the Token in needs.
How can I create a regex for finding the token?
I am doing a request to the server that looks like this
GET httb://SOMESERVERON.intranet:8080/secure/Dashboard.jspa
Cookie Data:
JSESSIONID=#IDNUMBER; atlassian.xsrf.token=#TOKENNUMBER
Request Headers: Connection: keep-alive Referer:
httb://SOMESERVERON.intranet:8080/plugins/servlet/gadgets/ifr?container=atlassian&mid=0&country=UK&lang=en&view=default&view-params=%7B%22writable%22%3A%22false%22%7D&st=atlassian%3AWYF9KCckTIxHKei%2BvMoCPKoa3LOkMGPilSEdaSqyqEFKIPnF0I3YcZDdKdElV0s%2B9%2FqBhMWhS2Qyvo7m0F2f3uTB3JBeKZF8Ou3EimeszE1Ms1IPMqDoYcVgPdF1CaQnnrANHwH1KhR1UxUlHed7VOyRPmfI26rO2FU65FQbvNuIZADHLRt1v8lF52vBeCqi6aSfyrfGau2lv3JDL4HVQv3dDmt%2FudFaX3a05CS94ncoGr0s&up_isPublicMode=false&up_isElevatedSecurityCheckShown=false&up_loginFailedByPermissions=false&up_externalUserManagement=false&up_loginSucceeded=false&up_allowCookies=true&up_externalPasswordManagement=&up_captchaFailure=false&up_isAdminFormOn=false&url=http%3A%2F%2Flrv142c3.europe.intranet%3A8080%2Frest%2Fgadgets%2F1.0%2Fg%2Fcom.atlassian.jira.gadgets%2Fgadgets%2Flogin.xml&libs=auth-refresh
Accept-Language: nl,en-US;q=0.7,en;q=0.3 Accept-Encoding: gzip,
deflate User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:34.0)
Gecko/20100101 Firefox/34.0 Accept:
text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8 Host:
http://SOMESERVERON.intranet:8080
So I know to look for this part
name="atlassian-token" content="TOKENKEY"
But what is the RegEx that I need to find the token and put it in a parameter that I can re use.
Regular Expression: name="atlassian-token" content="(.+?)"
Hope this will help.
For handling both JSESSIONID and atlassian-token cookies just add a HTTP Cookie Manager, JMeter is smart enough to deal with them automatically.

Google OpenID/federated login periodically fails

I'm developing a Django app that uses python-openid. The app is running on my development server at home.
Similar to stackoverflow's login mechanism, I'd like users to login to my website using their Google credentials.
The code I've implemented to do this, works well for a couple weeks, and then stops working. I get stuck during the login process on the following Google page: https://www.google.com/accounts/o8/ud with this message: "The page you requested is invalid." It'll randomly start working again, but fails every few weeks or so.
Going through Yahoo's login worked for months, and today has stopped working with the following message: "This page has expired, go back to the original page and please try again" on this page: https://open.login.yahooapis.com/openid/op/auth
Here is the request, as captured by LiveHttpHeaders for Google:
https://www.google.com/accounts/o8/ud
POST /accounts/o8/ud HTTP/1.1
Host: www.google.com
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.10) Gecko/2009042513 Ubuntu/8.04 (hardy) Firefox/3.0.10
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://127.0.0.1:8000/users/login/
Content-Length:907
openid.ax.if_available=ext1&openid.mode=checkid_setup&openid.ns=http://specs.openid.net/auth/2.0&openid.realm=http://127.0.0.1:8000/accounts/login/&openid.return_to=http://127.0.0.1:8000/users/login/finish/?janrain_nonce=2009-10-05T19%3A10%3A11ZtioiRm&openid.ax.count.ext1=unlimited&openid.ax.mode=fetch_request&openid.sreg.optional=email&openid.claimed_id=http://specs.openid.net/auth/2.0/identifier_select&openid.ns.sreg=http://openid.net/extensions/sreg/1.1&openid.ns.ax=http://openid.net/srv/ax/1.0&openid.identity=http://specs.openid.net/auth/2.0/identifier_select&openid.assoc_handle=AOQobUcnzec0bpeZRztjqPrr5TQUA0aPL7SIuOPOMgWxex2HRAP09AyJ&openid.ax.required=ext0&openid.ax.type.ext0=http://schema.openid.net/namePerson&openid.ax.type.ext1=http://schema.openid.net/contact/web/default
HTTP/1.x 400 Bad Request
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
I'm not sure what's going on here, and would love some help.
It looks like the code you are using is generating a bad URL request. The real URL is https://www.google.com/accounts/o8/id, so try to fix the "ud" at the end changing it by an "id".
Hope this helps!
you can construct the uri and redirect the user to the uri with GET method. If you doing POST google expects some headers which I think it was not mentioned docs. Check the sample request. I tried with GET without python-openid it works pretty well.
You might take a look at the redirect_uri and the state inside to see if they match. I remember having the issue of having mismatched state sometimes ago with Google Login.
Btw if you use Django, I would recommend using social-app-django which is currently active and supports multiple social login options (if at some point you consider adding more social login providers).