📜 ⬆️ ⬇️

A few thoughts on secure code

In this article I would like to describe some seemingly obvious security problems, which, however, are not always fully resolved by programmers. Basically, my thoughts are about web development, but some topics are relevant to other applications. In the article, I operate with examples of asp.net and C #, but I am sure that all the problems are also relevant for other platforms and languages.

Forget about user


Not the user calls your method, but other methods. The user is a living person who presses buttons, he does not know anything about your methods. The real misconception is to associate a method call with a user.

Very often, programmers are imbued with thoughts about the user when they work in visual environments. Environments such as Delphi or Visual Studio make it easy to determine the event handling of controls with which the user works. It is easy to be tempted to double-click in the form editor on the button to set an action that would determine the processing of the user's actions. Formally, this is correct. But consider an example:
protected void Button1_Click ( object sender, EventArgs e)
{
(sender as Button) .Text = "Hello" ;
}
private void MyMethod ()
{
Button1_Click ( null , new EventArgs ());
}
* This source code was highlighted with Source Code Highlighter .


This example only works as long as we are confident that the events are controlled by a mythical user. But we remain helpless in the face of the real state of affairs, when code is not controlled by the user, but by other code.
')

No context, only security requirements


When dealing with web applications, forget that some functions can be called or controls are pressed only when something happens somewhere. That the user made the login, that today is Monday, that the button was pressed by Boris, and not Peter. All this is an illusion, which leads to the idea that you are dealing with a user, and not with code.

For example, we have a page on which, after the login, a control panel appears with some functionality. The biggest mistake may be your belief that this control panel cannot be used by an unauthorized user. This is such a simple delusion that many do not even think about it.

On my project there are such pages with a panel, caching is forbidden on the pages, and in the case of an exceptional situation it is registered in the database. And even taking into account the fact that the page cannot seem to be placed in the cache, I record attempts to use a panel that is supposedly inaccessible by unauthorized users.

And here there is a very simple explanation for this: the user Boris can simply not close the page for a couple of days, and then turn to it again when his session on the server has long been completed. And, maybe, instead of him, Peter will do it, and the consequences can already be different: from a simple window with an error and an unpleasant aftertaste to the abduction or compromise of Bori's data by the villain Petya.

What does it mean? It's simple: forget the context, follow the rules of security.

The code is always called "evil" code.


It looks like paranoia, but it is. No one can ever be sure what code and how your method will call. You can be sure of only one thing - your code works in a volatile environment and requires mandatory validation of all required parameters: method arguments, global variables, configuration file data, query string, etc.

So we will remake the previous example as it deserves it:
protected void Button1_Click ( object sender, EventArgs e)
{
Button senderButton = (sender as Button);
if (senderButton! = null )
senderButton.Text = "Hello" ;
}
private void MyMethod ()
{
Button1_Click ( null , new EventArgs ());
} * This source code was highlighted with Source Code Highlighter .


Exceptional situations deserve exceptional action.


It is worth remembering once and for all:
1. the return method of error codes, instead of calling an exception - is evil;
2. The exception is not a synonym for error.
Here you should immediately decide what is actually considered an error code. If the code returns a description of the situation, it is a description of the situation, but if the code returns a value in the event of a situation when it could not continue, then this is the error code, the call of which should be replaced with an exception call.

For example:
• the code checks the existence of the required file and returns a boolean value, where false is a sign that the file does not exist;
• the code reads the contents of the file, but at some point it cannot read the block and terminates, returning a boolean value or the value of some enumeration;
• the code checks the presence of the image file and if it does not find it, it terminates execution without returning any value or by calling an exception.
In the first case, returning a boolean value is the task of the method, in the second, returning the description of an exceptional situation. The first method does not need to be changed, the second one needs to be redone to the exception call, having refused to return any value. The third case is a common case when the error situation is insignificant in the general context of the work being done. Generating an exception in this place would stop the execution of important code because of a trifling moment, which is unacceptable.

Determining the degree of exclusivity of an error is not always an easy task. I recommend the following rules:
• the return of the error code is valid only in methods that test the situation for an error;
• if the code cannot be executed to the end due to an error, an exception must be generated;
• if the code within the context of the problem being solved ran into a previously known possible problem, then it makes sense either to complete the code and return the description of the situation, or to ignore the problem.

All answers are negative.


Look at the following code:
enum access
{
Granted
Restricted
}
private Access CheckLogin ( string password)
{
Access result = Access.Granted;

try
{
if (password! = GetValidPassword ())
result = Access.Restricted;
}
catch
{
}

return result;
} * This source code was highlighted with Source Code Highlighter .


The code is obviously stupid, but this is a simplification, and in life you can see more complex structures, the essence of which boils down to this code. What's wrong with that? It's just the fact that if an exception occurs in the GetValidPassword method, any user with any password will get access.

To return the result, I defined several rules:
• in minor methods that will not cause exceptions in case of problems, avoid returning non-nullable types, except boolean values;
• all methods that return values ​​must first of all initialize this value with the most negative or safe option (for nullable types, this can be null, for booleans, false, for enums, the most negative value like Access.Restricted);
• All methods must have one point for returning values.
As a result, we can distinguish such a pattern:
private Access MyMethod ()
{
Access result = Access.Restricted;

// put your code here, there should be no return calls in the code, just change the value of result

return result;
}
* This source code was highlighted with Source Code Highlighter .


Conclusion


The article touched upon the issues of writing safe code, as a result, the following rules can be identified:
• your code works in a hostile environment, ensure all security requirements in each method;
• check whether the environment in which your code will work, with what parameters it has been called is valid, remember that it is not the user who is doing this, but another code;
• always by default return safe values ​​in the context;
• all methods must have one exit point;
• use exceptions in exceptional situations to guarantee interruption of code execution;
• ignore or handle minor issues to accomplish an important task.

Source: https://habr.com/ru/post/26506/


All Articles