كيفية إمساك المتسللين في التعليمات البرمجية الخاصة بك

ماذا ستفعل إذا كان المتسللون يسيئون استخدام برنامجك في الإنتاج؟

هذا ليس سؤالا افتراضيا. ربما يفعلون ذلك الآن.

قد تفكر في جميع خيارات التصميم الآمنة التي قمت بها ، أو الأساليب الوقائية التي طبقتها ، لذلك لا داعي للقلق.

إذا كان الأمر كذلك ، فهذا رائع - حتى إذا كانت هناك دائمًا أشياء يتم التغاضي عنها ، يجب أن تفكر دائمًا في أمان نظامك.

ولكن هناك فرق كبير بين منع الأخطاء الأمنية والتسامح مع المحاولات الخبيثة.

ماذا عن القبض على المتسللين الذين يحاولون اختراق برامجنا والتصرف معهم؟ في هذا المنشور ، سأحاول أن أقدم لك أمثلة عملية وبسيطة على اكتشاف سلوكيات الهاكر النموذجية في شفرتك في وقت مبكر.

لماذا نلتقط المحاولات الخبيثة؟

ألا يكفي منع الأخطاء الأمنية؟ يمكنني سماعك تقول ، "طالما أكتب كودًا آمنًا ، لا يهمني ما إذا كان المتسللون يلعبون ببرنامجي الصلب أم لا. لذا ، لماذا يجب أن أهتم بالمحاولات الخبيثة؟ "

دعنا أولاً نجيب على هذا السؤال الصحيح.

من الصعب الحفاظ على برنامج معقد إلى حد ما آمنًا طوال الوقت. المزيد من التعقيد يعني المزيد من نقاط الضعف المحتملة التي قد يسيء المتسلل إليها المخترق أثناء تصميم الشفرة أو تنفيذها أو نشرها أو صيانتها.

ما عليك سوى إلقاء نظرة على أرقام مكافحة التطرف العنيف على مر السنين. إنه كثير:

علاوة على ذلك ، نظرًا لطبيعته ، فإن الخطأ الأمني ​​ليس مجرد عنصر عادي في الأعمال المتراكمة. هناك بعض العواقب الوخيمة إذا تم استغلال ثغرة أمنية: فقدان الثقة ، أو السمعة السيئة ، أو حتى الخسارة المالية.

لذلك ، توجد أفضل الممارسات الأمنية مثل OWASP Application Security Verification Standard (ASVS) أو إرشادات Mozilla للتشفير الآمن من أجل مساعدة المطورين على إنتاج برامج آمنة.

ومع ذلك ، نظرًا لظهور طرق جديدة لتجاوز ضوابط الأمان الحالية أو ظهور نقاط ضعف جديدة على أساس يومي تقريبًا ، هناك إجماع حول مجتمع الأمان على أنه "لا يوجد أمان بنسبة 100٪." لذلك يتعين علينا دائمًا توخي الحذر والاستجابة لأخبار الأمان والتحسينات.

هناك أيضًا شيء آخر يمكننا القيام به لضمان أمان البرامج: ملاحظة المتسللين في أقرب وقت ممكن ، قبل أن يفعلوا شيئًا لا نتوقعه أو حتى نعرف عنه. علاوة على ذلك ، فإن تتبع سلوكهم الضار على مدى فترة زمنية طويلة يجعلنا أكثر استباقية.

هناك مفهوم شائع لمركز العمليات الأمنية (SOC) على هذا المنوال - SOCs هي نوع من الفريق في مؤسسة يتم الاستعانة بمصادر خارجية أو داخلية. مهمتهم هي مراقبة الحالة الأمنية للمنظمة باستمرار. يفعلون ذلك عن طريق الكشف عن حوادث الأمن السيبراني وتحليلها والاستجابة لها.

تبحث فرق SOC عن الأنشطة غير الطبيعية ، بما في ذلك الحالات الشاذة في أمان البرامج. إن فكرة ملاحظة هجوم إلكتروني ناجح أو فاشل والرد عليه يمنح المؤسسات اليد العليا ضد التهديدات ، مما يقلل في النهاية وقت الاستجابة للهجمات من خلال المراقبة المستمرة.

تكون SOC قوية فقط من خلال المدخلات الغنية والجودة التي تحصل عليها من مصادر مختلفة لمكونات تكنولوجيا المعلومات. نظرًا لأن برنامجنا يعد أيضًا جزءًا مهمًا من المخزون ، فإن الإنذارات الأمنية المناسبة بسبب السلوكيات غير الطبيعية التي يرسلها برنامجنا إلى فرق SOC لا تقدر بثمن.

كيفية التحقق من السلوكيات غير الطبيعية

في ما يلي عدد من عمليات الفحص والضوابط التي يمكننا تنفيذها في جميع أنحاء التعليمات البرمجية الخاصة بنا والتي تكشف عن السلوكيات الخبيثة وغير الطبيعية.

قبل أن نبدأ ، أود التأكيد على أنني لا أقدم هنا حلولًا معقدة مثل جدار حماية تطبيقات الويب (WAF). بدلاً من ذلك ، سأحاول فقط أن أوضح لك أن الشروط البسيطة ، والتعامل الذكي مع الاستثناءات ، والإجراءات المماثلة التي لا تتطلب جهدًا كبيرًا في التعليمات البرمجية الخاصة بك يمكن أن تساعدك على ملاحظة السلوكيات غير الطبيعية بمجرد حدوثها.

دعنا نحفر.

طول صفري أو إرجاع فارغ

أول إجراء يمكننا اتخاذه لاكتشاف إجراء ضار هو التحقق من المجاميع الصفرية أو المرتجعات الفارغة.

إليك مقطع رمز بسيط لتوضيح النقطة:

Receipt receipt = GetReceipt(transferId); if (receipt == null) { // what does this mean? // log, notify, alarm }

هنا ، نحاول الوصول إلى إيصال تحويل معين مقدم من مستخدمينا النهائيين من خلال transferIdالمعلمة.

من أجل منع أي شخص من الوصول إلى إيصالات شخص آخر ، دعنا نفترض أنه داخل هذه GetReceiptالطريقة ، فإن مطورنا ذكي بدرجة كافية للتحقق مما إذا كان transferIdالمستخدم ينتمي حقًا إلى المستخدم الحالي.

التحقق من الملكية هو أفضل ممارسة أمنية جيدة.

دعنا نفترض أيضًا أننا متأكدون من أن كل تحويل يجب أن يحتوي على إيصال واحد على الأقل ذي صلة ، لذا فإن عدم الحصول على أي شيء في وقت التشغيل أمر مريب. لماذا ا؟ لأن الحصول على إيصال فارغ يعني أن المقدم transferIdلا ينتمي إلى أي تحويل ينفذه المستخدم الحالي.

بعبارة أخرى ، قدم المستخدم الحالي transferIdرمزًا مزيفًا لكودنا وينتظر رؤية المحتوى إذا كان transferIdذلك يتعلق بمعاملة شخص آخر.

ونظرًا لأن لدينا التحكم المناسب في الملكية ، فإن GetReceiptالطريقة تُرجع إيصالًا فارغًا أو فارغًا. هذا حيث يتعين علينا اتخاذ بعض الإجراءات الأمنية.

لن أخوض في تفاصيل الإجراءات الأمنية في هذا المنشور. ومع ذلك ، فإن تسجيل الأمان و / أو إرسال الإخطارات التفصيلية وأنظمة إدارة الأحداث والمعلومات الأمنية (SIEM) هما اثنان منهم.

فيما يلي مثال آخر على كيفية السماح لنا بفحص القيمة الفارغة بالاستيلاء على محاولة ضارة.

ضع في اعتبارك أن لدينا نقاط النهاية الثلاثة التالية ، ShowReceiptو Success، و Error:

// ShowReceipt endpoint if(CurrentUser.Owns(receiptId)) { Session["receiptid"] = receiptId; redirect "Success"; } else { redirect "Error"; }
// Success endpoint receiptId = Session["receiptid"]; return ReadReceipt(receiptId);
// Error endpoint return "Error";

هذا تطبيق بسيط يعرض محتوى إيصال المستخدم.

في ShowReceipt، السطر الأول مهم. يتحقق مما إذا كان المستخدم النهائي يرسل لنا رسالة صالحة receiptIdللاطلاع على محتوياتها. بدون هذا التحكم ، يمكن لأي مستخدم ضار توفير أي receiptIdمحتوى والوصول إليه.

لكن مكان العبارة في السطر الثالث لا يقل أهمية. إذا قمنا بتحريك هذا السطر قبل عبارة if مباشرة ، فلن يؤدي ذلك إلى كسر أي شيء. ومع ذلك ، قد يؤدي ذلك إلى نفس مشكلة الأمان التي كنا نحاول تجنبها عن طريق التحقق مما إذا كان المستخدم النهائي يطلب إيصالًا صالحًا أم لا.

يرجى قضاء بعض الوقت للتأكد من أنك تفهم سبب حدوث ذلك.

الآن ، من الجيد وضع هذا الخط في المكان الصحيح وهذا يخلق فرصة أخرى لملاحظة المحاولات الخبيثة. ثم ، في Successنقطة النهاية ، ماذا يعني إذا حصلنا على قيمة خالية receiptIdمن Session؟

هذا يعني أن شخصًا ما يتصل بنقطة النهاية هذه ، بعد أن قدم طلبًا ShowReceiptلنقطة النهاية مع شخص آخر receiptId. حتى لو حصلوا على Errorإعادة توجيه بسبب التحقق من الملكية!

بالطبع مع السيطرة التي لدينا في السطر الأول ، هذا مستحيل.

لذا ، تعد Successنقطة النهاية مكانًا رائعًا لكتابة إدخال في سجل الأمان وإرسال أي إشعارات إلى حلول المراقبة الخاصة بنا عندما نحصل على قيمة خالية receiptIdمن Session.

// Success endpoint (Revisited) receiptId = Session["receiptid"]; if(receiptId == null) { // log, notify, alarm } return ReadReceipt(receiptId);

معالجة الاستثناءات المستهدفة

Exception handling is maybe the most important mechanism for developers to respond to any anomalous condition during the execution of the program.

Most of the time the main opportunity it provides is cleaning up resources that were borrowed such as file/network streams or database connections upon unexpected problems. This is a fail-safe behavior that lets us write more reliable programs.

In parallel we can effectively use runtime exceptions to notice malicious attempts towards our software.

Here are some popular sources of weakness where we can utilize related exceptions to notice fishy behavior:

  • Deserialization
  • Cryptography
  • XML Parsing
  • Regular Expression
  • Arithmetic Operations

The list is not complete, of course. And here I’ll go through only a few of these APIs.

Let’s start with Regular Expressions. Here’s a code block that applies a strict validation method on a user input:

if(!Regex.IsMatch(query.Search, @"^([a-zA-Z0-9]+ ?)+$")) { return RedirectToAction("Error"); }

The regular expression pattern used here is a solid whitelist one, which means it checks what is expected as an input. Not the other insecure way around, which is checking what is known to be bad.

Still, here’s a much secure version of the same code block:

if(!Regex.IsMatch(query.Search, @"^([a-zA-Z0-9]+ ?)+$", RegexOptions.Compiled, TimeSpan.FromSeconds(10))) { return RedirectToAction("Error"); }

This is an overloaded version of the IsMatch method of which the last argument is the key.

It enforces that the execution of the regular expression during runtime can not exceed 10 seconds. If it does, that means something suspicious is going on since the pattern used is not that complicated.

There’s an actual security weakness that might be used to abuse this pattern called ReDoS, though I won't go into the details of it here. But in short, an end-user can send the following string as the search parameter and make our back-end miserable, spending an awful amount of CPU power in vain.

Notice the quotation mark at the end (and don’t try this in production!):

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA!

The question is, what happens when the execution time actually exceeds 10 seconds?

The .NET environment throws an exception, namely RegexMatchTimeoutException. So, if we specifically catch this exception, we now have the opportunity to report this suspicious incident or do something about it.

Here’s the final code block to that end:

try { if(!Regex.IsMatch(query.Search, @"^([a-zA-Z0-9]+ ?)+$", RegexOptions.Compiled, TimeSpan.FromSeconds(10))) { return RedirectToAction("Error"); } } catch(RegexMatchTimeoutException rmte) { // log, notify, alarm }

Another important venue where we can utilize exceptions is XML parsing. Here’s an example code block:

XmlReader xmlReader = XmlReader.Create(input); var root = XDocument.Load(xmlReader, LoadOptions.PreserveWhitespace);

The input XML is fed into XmlReader.Create, and then we get the root element. Hackers can abuse this piece of code by providing some malicious XML files, which, when parsed by the above code, gives ownership of our servers to them.

Scary, right? The security bug is called XML External Entity (XXE) attack, and as with the Regular Expression exploit, I won't go into all the details here.

However, in order to prevent that super critical weakness, we ignore the usage of Document Type Definitions (DTD) through the XmlReaderSettings. So now, there’s no possibility of XXE security bugs anymore.

Here’s the secure version:

XmlReaderSettings settings = new XmlReaderSettings(); settings.DtdProcessing = DtdProcessing.Ignore; XmlReader xmlReader = XmlReader.Create(input, settings); var root = XDocument.Load(xmlReader, LoadOptions.PreserveWhitespace);

We can leave the code just like this and move on. However, if a hacker still tries to abuse this attack in vain, it's better that we can catch this behavior and produce an invaluable security alert:

try { XmlReaderSettings settings = new XmlReaderSettings(); settings.DtdProcessing = DtdProcessing.Ignore; XmlReader xmlReader = XmlReader.Create(input, settings); var root = XDocument.Load(xmlReader, LoadOptions.PreserveWhitespace); } catch(XmlException xe) { // log, notify, alarm }

Moreover, in order to prevent false positives, you can further customize the catch block by using the message content provided by the XmlException instance.

There’s a general programming best practice that denies using generic Exception types in catch blocks. What we have shown is also a good supporting case for this. Same goes with another best practice that denies using empty catch blocks, which is effectively doing nothing when an abnormal behavior occurs in our code.

Apparently though, instead of empty catch blocks, here we have a very solid opportunity to react to malicious attempts.

Normalization on Inputs

By definition, normalization is to get the simplest form of something. In fact, canonicalization is the term used for this purpose. But it is hard to pronounce, so, let's stick to normalization.

Of course, “the simplest form of something” is a little bit abstract. What do we mean by the “simplest form”?

It is always good to show by example. Here is a string:

%3cscript%3e

According to the URL encoding, this string is not in its simplest form. Because if we apply URL decoding on it, we get this one:

This is the simplest form of the original string according to URL encoding transformation standard.

How do we know that? We know it not because it is understandable to us now. We know it because if we apply URL decoding again, we will get the same string:

And that means URL decoding does not successfully transform it anymore. We hit the simplest form. Normalization can take more than one step, as originally the encoding might be applied more than once.

URL encoding is just one example of the transformation used for normalization, or in other words, decoding. HTML encoding, JavaScript encoding, and CSS encoding are other important encoding/decoding methods widely used for normalization.

Over the years, attackers find genuine techniques to bypass defense systems. And one of the most prevalent techniques they utilize is encoding. They use crazy encoding techniques on their original malicious inputs, in order to fool defenses around applications.

History is full of these demonstrations, and you can read the details of one of the most famous ones called Microsoft’s infamous IIS dotdot attack that took place in the early 2000s.

Since hackers rely on encoding techniques substantially when they are sending malicious inputs, normalization can be one of the most effective and easy ways to seize them.

Here is the rule of thumb: we recursively apply URL/HTML/CSS/JavaScript decoding to user input until the output no longer changes. And if the output is a different string than the original input, that means we may have a possible malicious request.

Here’s a simplified version of legendary OWASP ESAPI Java that implements this idea:

int foundCount = 0; boolean clean = false; while(!clean) { clean = true; // whatever codes you want; URL/Javascript/HTML/... Iterator i = codecs.iterator(); while (i.hasNext()) { Codec codec = (Codec)i.next(); String old = input; input = codec.decode(input); if (!old.equals(input)) { if (clean) { foundCount++; } clean = false; } } }

When the code block ends, if the value of foundCount is bigger or equal to 2, that means what? It means someone is sending multiple encoded input to our application, and the odds of this happening is really rare.

Normal users do not send multiple encoded strings to our application. There is a high probability that this is a malicious user. We have to log this event with the original input for further analysis.

The above mechanism, while part of the software itself, functions like a filter in front of the application. It runs on every untrusted input and gives us an opportunity to know about malicious attempts.

However, you may be suspicious about the additional delay this way of validation incurs. I understand if you don’t want to opt-in.

Here's another example of using normalization as a means to seize malicious attempts during file uploads or downloads. Consider the following code:

if (!String.IsNullOrEmpty(fileName)) { fileName = new FileInfo(fileName).Name; string path = @"E:\uploaded_files\" + fileName; if (File.Exists(path)) { response.ContentType = "image/jpg"; response.BinaryWrite(File.ReadAllBytes(path)); } }

Here we get a fileName parameter from our client, locate the image it points to, read, and present the content. This is a download example. It might also have been an upload scenario.

Nevertheless, in order to prevent the client manipulating the fileName parameter to their heart’s content, we utilize the Name property of the FileInfo class. This will only get the name part of the fileName, even if the client sends us anything other than what we expect (i.e. a file name with forged paths such as below):

../../WebSites/Cross/Web.config

Here the malicious client wants to read the contents of a sensitive Web.Config file by using our code. Getting only the file name part, we get rid of this possibility.

That is good but there is still something we can do:

if (!String.IsNullOrEmpty(fileName)) { string normalizedFileName = new FileInfo(fileName).Name; if (normalizedFileName != fileName) { // log, notify, alarm response = ResponseStatus.Unauthorized; } string path = @"E:\uploaded_files\" + fileName; if (File.Exists(path)) { response.ContentType = "image/jpg"; response.BinaryWrite(File.ReadAllBytes(path)); } }

We compare the normalized version of fileName with itself (the original input). If they differ, that means someone is trying to send us a manipulated fileName and we take appropriate action.

Normally the browser just sends the uploaded file name in its simplest form with no transformation.

For the sake of the argument, we may not even use the file name when the user uploads a file. We may be generating a GUID and use that instead.

Nevertheless, applying this control to the provided file name still matters, because hackers will definitely poke with that parameter no matter what.

Invalid Input Against Whitelists

Whitelisting is “accepting only what is expected”. In other words, if we come across some input that we do not expect, we reject it.

This input validation strategy is one of the most secure and effective strategies we have to this date. By using this strategy consistently throughout your software, you can close a lot of known and unknown venues that a malicious user can attack you.

This way of building a software is like building a closed castle with only thoroughly controlled doors opening outside, if that makes any sense.

OK, back to our topic.

Let’s analyze whitelisting with a simple scenario. Assume that our users have the freedom to choose their own, specific usernames when registering. And prior to coding, as a requirement we were informed how a username should look like.

Then, in order to comply with this requirement we can easily devise some rigid rules to apply against the username input before we accept it. If the input passes the test, we take in. Otherwise, we reject the input.

The whitelist rules may be in different forms, though. Some may contain a list of expected hard-coded values, others may check whether the input is integer or not. And others may be in the form of regular expressions.

Here is an example regular expression for usernames:

^[a-zA-Z0-9]{4,15}$

This regular expression is a very rigid whitelisting pattern. It matches with every string whose characters are nothing but a-z, A-Z, or 0-9. Not only this, but the length of the input should be minimum of 4 characters and maximum of 15 characters.

The hat at the beginning and dollar character at the end of the regular expression denote that the match should occur for the whole input.

Now assume that at runtime we get the following input which won’t pass our regular expression test:

o'neal

Does that mean our software is facing a hacker?

The input seems innocent. However, it might also be the case that a malicious user is just trying the existence of an SQL injection security bug before getting into the action, which is also known as reconnaissance.

Anyway, it’s still hard to deduce any malice from this particular case.

However, we can still seize the hackers using other forms of failed whitelists, such as failed input attempts against a list of expected hard-coded values.

An excellent example is JSON Web Token (JWT) standard. We use JWT when we want third parties to send us a claim that we can validate and then trust the data inside.

The standard has a simple JSON structure: a header, a body and a signature. The header contains how this particular claim should be produced and therefore validated. The body contains the claim itself. The signature is there for, well, validation.

For instance, when we get the following token from a third part, such as a user, we validate it using the algorithm it presents in the header value.

In this instance, the token itself tells us that we should use cryptographic hash HMACSHA256 algorithm (HS256 in the token is a short version) on both the header and body data to test whether it produces the same signature given.

If it produces the same signature value, then the token is authentic and we can trust the body:

// Header { "alg" : "HS256", "typ" : "JWT" } // Body { "userid": "[email protected]", "name": "John Doe", "iat": 1516239022 } // Signature AflcxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5g

There are various external libraries that we can easily use to produce and validate JWTs. Some of them had a serious security bug which let any JWT to be taken as an authentic token.

Here’s what went wrong with those libraries.

What happens when a token that we should validate contains a header like below? I just present the header here, but it also contains body and signature parts:

// Header { "alg" : "None", "typ" : "JWT" }

It seems that for that specific token some of those JWT validation libraries just accept the body as it is without any validation, because None says that no algorithm is applied for signature production.

To put this into perspective, that means any end user can send us any userid inside the token and we will not apply any validation against it and let them login.

The best way to avoid this and similar security problems is to keep a valid list of algorithms on our side. In this case the list may contain only one valid algorithm.

Moreover, it's better not to process the algorithm we get inside the header part of the JSON Web Token, whatever it might be.

But as you might have already guessed, there’s a huge opportunity here. We may just get the algorithm value from the header part and check even if we won’t use it. If the value is anything other than we expect, let’s say HS256, that means someone is messing around with us.

The same method can be used for any list of hard-coded values presented to the end user and one of which we expect to get as an input.

For example, if we provide a list of cities in a select box, we are sure that we will get back one of them when the form is posted. If we get a completely different value, there’s surely something wrong with the behavior of the user or automated tool we are facing.

Actions Against AuthN and AuthZ

One of the most critical parts of software from a security point of view are the authentication and the authorization mechanisms. These are places where we enforce that only the parties we know of access the application and they access certain parts within their roles.

In other words, our users shouldn’t use certain parts of our application without any credential validation and they shouldn’t access parts where they don’t have any privileges.

There are various attack scenarios against both of the mechanisms, however, the most obvious one against authentication is brute forcing. It is trying a set of pre-populated or generated on the fly credentials one after another in the hope that one or more of them would work.

Of course there are well-known ways to prevent such attacks: using CAPTCHAs or applying throttling on problematic IP addresses or usernames.

Usually authentication attacks are well-known and when noticed are already logged and possibly fed into the security monitoring systems.

The same is possible with attacks against authorization.

It’s easy to produce a security log and an alarm when our application returns an 403 response to our users. This well-known HTTP response is the indicator of an authorization problem, so it’s wise to log it.

However, both the authentication and the authorization cases so far have the potential to produce false alarms. However, I still encourage logging and producing alarms whenever these occur.

Now, let’s concentrate on a more solid case. Whenever we use Model-View-Controller (MVC) frameworks, we utilize the built-in auto-binding feature for our Action method parameters. So, the MVC framework we are using is in charge of binding parameters in HTTP requests onto our model objects automatically.

This is a great relief for us since getting each user input by using the low-level APIs of a framework really becomes tedious after some time.

What happens if this auto-binding becomes too permissive? Assume that we have a User model. It would probably have at least ten or twenty member fields. But for clarity, let’s say it has a FullName and a IsAdmin member fields.

The second member field will denote if a particular user is administrator or not:

public class User { public string FullName { get; set; } public bool IsAdmin { get; set; } }

In order for users to update their own profile, we prepare a View including the appropriate form and bindings.

At last, when the form is submitted, a controller action will auto-bind the HTTP parameters to a User class instance. Then, perhaps it will save it to the database just like below:

[HttpPost] public Result Update(User user) { UserRepository.Store(user); return View("Success"); }

Obviously here, a malicious non-administrative user may also set values of unwanted model members, such as IsAdmin. Since the binding is automatic, our malicious user can make themselves administrator by requesting a simple HTTP POST request to this action!

By using the MVC pattern, every model we use in action method parameters becomes fully visible and editable to end-users.

The best way to prevent this is using extra ViewModels or DTO objects for Views and Actions and include only the permitted fields. For example, here is a UserViewModel that only contains editable fields of User model class.

public class UserViewModel { public string FullName { get; set; } }

So, the end user, albeit she can add an additional IsAdmin parameter to the HTTP POST request, that value will not be used at all to result in a security problem. Excellent!

But wait, there’s a golden opportunity here to seize sophisticated hackers. How about we still include IsAdmin property in our UserViewModel, but produce a security log and maybe alarms when the setter is called:

public class UserViewModel { public string FullName { get; set; } public bool IsAdmin { set { // log, alarm, notify } } }

Just make sure that we don’t use this member field when we are creating a User model class instance out of this UserViewModel instance.

Miscellaneous

It is impossible to list or classify every possible case where we can place our little controls to notice any hacking attempts as early as possible. However, here are some of the other opportunities we have:

  • If our application provides a flow of actions which should be followed in a specific order, then any invalid order of calling indicates an abnormal behaviour.
  • Injection attacks are one of the most severe security bug categories that stem from insecure code and data concatenation. Cross Site Scripting (XSS), SQL Injection, and Directory Traversal are some common bugs in this category. Once we use secure constructs like contextual encodings, whitelist validation, and prepared statements, then we get rid of them. However, unfortunately, there are no simple and non-blacklist ways to seize the hackers who are still trying to abuse these security bugs once they are fixed.
  • يعد إعداد الفخاخ أيضًا طريقة صالحة للقبض على المحاولات الخبيثة ، لكنني ضد ذلك إذا استغرق الجهد وقتًا طويلاً أو من المحتمل أن ينتج إنذارات خاطئة. على سبيل المثال ، من الممكن تضمين الروابط المخفية (عرض: لا شيء) في صفحات الويب الخاصة بنا وتشغيل تسجيل الأمان عند الوصول إلى هذه الروابط بواسطة ماسحات أمان آلية (لأنها تحاول الوصول إلى كل رابط يمكنهم استخراجه). ومع ذلك ، قد ينتج عن هذا أيضًا إنذارات خاطئة لبرامج الزحف الشرعية ، مثل Google. ومع ذلك ، هذا اختيار تصميم وهناك الكثير من المصائد التي يمكن ضبطها ، مثل غير الموجودة ولكن من السهل تخمينها:
    • اسم المستخدم ، أزواج كلمة المرور ، على سبيل المثال المشرف سيئ السمعة: المشرف
    • مسارات URL الإدارية ، على سبيل المثال / admin
    • رؤوس ، معلمات HTTP ، على سبيل المثال IsAdmin

استنتاج

"الغفران ليس الموافقة على ما حدث. إنها تختار أن ترتفع فوقها ". روبن شارما

إنه لمن السذاجة التي لا تُغتفر السماح للمحاولات الخبيثة تجاه برنامجنا بالمرور دون أن يلاحظها أحد بينما لدينا بالفعل الأدوات تحت حزامنا للقيام بخلاف ذلك. المسامحة هي صفة أخلاقية عليا ، لكن علينا أن نكون على رأس الأنشطة الخطرة المتعلقة بمدونتنا.

على الرغم من الجوانب الفوضوية لتطوير البرمجيات ، فإن تطوير التعليمات البرمجية الآمنة يعد مهارة بقاء مهمة في هذا العالم المليء بالقرصنة.

علاوة على ذلك ، لدينا فرصة لتحسين هذه المهارة بشكل أكبر من خلال ملاحظة الأنشطة الضارة بطريقة دقيقة في التعليمات البرمجية الخاصة بنا وإنتاج إدخالات سجل الأمان وإنذارات لفرق SOC.

إن القيام بشيء ما بشأن السلوكيات الضارة في التعليمات البرمجية الخاصة بنا ، كما قرأت في هذه المقالة ، هو مجرد أحد أخطاء الترميز التي تؤدي إلى إساءة استخدام المخترقين. أنا أشجعك على التحقق من التدريبات عبر الإنترنت لأخطاء الترميز التي يسيء استخدامها المتسللون من أجل إتقان بقية هذه الأخطاء.