MIT course "Computer Systems Security". Lecture 11: "Ur / Web programming language", part 1
Massachusetts Institute of Technology. Lecture course # 6.858. "Security of computer systems". Nikolai Zeldovich, James Mykens. year 2014
Computer Systems Security is a course on the development and implementation of secure computer systems. Lectures cover threat models, attacks that compromise security, and security methods based on the latest scientific work. Topics include operating system (OS) security, capabilities, information flow control, language security, network protocols, hardware protection and security in web applications.
Nikolai Zeldovich: let's start guys! So today we will talk about a completely different and principled approach to creating secure web applications. It's about a system called Ur / Web. Now our guest, Adam Chipala, who is the author of this system, a professor at MIT, will tell you about the system he created. ')
Adam Chipala: I want to get to the demonstration as soon as possible. But before that I will show some slides to explain the content of this system. You have probably already received some ideas about this from the summary of today's lecture.
So what is Ur / Web? It is always helpful to begin by explaining what the name of the topic means. Ur / Web is primarily a programming language for creating web applications. That's what the Web is in its title. This is a kind of full stack system that does everything you need to build web applications. Ur means the new universal programming language that is used to implement these web features.
The whole point of Ur / Web is that instead of using a general-purpose programming language, a library, and traditional frameworks for creating web applications, all of this is already integrated into the custom programming language Ur / Web. It is a language that at compile time includes compilation, not interpretation. And the compiler, in a sense, understands what a web application should do. It will indicate the errors you make, unlike the regular Java compiler, which does not understand where you have errors.
There are three basic principles that I tried to use when developing this language: programming efficiency, security and performance, especially on the server side, for scaling. In this context, the second is most relevant.
In most cases, users of your application will not notice small performance problems on the client side, but even a small problem on the server side may force you to buy many more servers than necessary.
At the moment there are already several Ur / Web users, although there are not as many of them as those who use other programming languages. But at least this is the only commercial web application that is an RSS reader and which supports such exotic features as displaying comments. There is also a URL, invented by a non-native English speaker, who now regrets such a name. It is called BazQux Reader, a combination of the tactical skills of the hacker community. This application already has several thousand paid users. And it seems that it is much more pleasant to deal with it than with what is done using CSS. This is proof that this can be done with Ur / Web.
Feel free to interrupt me with questions at any time, although I probably did not yet understand what might cause questions. Thus, the main success of Ur / Web sales is that it has a very high-level programming model, which is very different from Django, which you know about from previous lectures. And he has a good security history.
Some features that you would like to have for security are already integrated into the system, so you don’t have to work hard to ensure your program’s security. I will tell you more about this in the near future.
In addition, this language provides high performance on the server side, even compared to the more popular tools for creating web applications, I think you have already heard about it. The reservation is that we will probably need to learn more ideas from functional programming languages, such as Haskell, before we start using Ur / Web.
I looked at the questions and answers for this lesson, and about a fifth of the students complained about the functional parts of programming that are difficult to perform. I'm sorry, but in the world of functional programming there are so many good ideas that it would be difficult not to start from this very moment, gradually adding more complex things to it. But I will try not to require strict knowledge of the material, which I will talk about today.
Thus, this programming model is indeed closely related to static typing. And this is not just static typing, as in the Java language, which has a relatively inexpressive, awkward type system, but static typing, similar to that used in Haskell or Apache Camel. This typing is one of the ways in which the compiler understands what you are doing and catches errors in its program.
It turns out that the main language Ur, on which Ur / Web is built, has a very expressive system of static typing. So much of what Ur / Web does does actually provide libraries without special compiler support. For example, we taught the compiler how to check the type of SQL queries without creating rules for SQL input into the compiler. They can be encoded as libraries and use the standard type of validation to ensure that your SQL queries follow the rules of SQL.
The most relevant in this context is ensuring a high level of security — most of the most common security vulnerabilities are not possible when programming on Ur / Web. You can say goodbye forever to malicious code injection attacks and cross-site scripting attacks. You can allow scary-looking flag names to do the most awful things you can do in a web application, even if you do invoke some “black magic” using the functions of someone else's interface.
There are several other security-specific properties that I will discuss later. Performance is also very good. The compiler is primarily optimized for generating source code for domains and is much more productive than manual code written in C.
Therefore, he understands what the web application does, and can optimize some things that a traditional generic compiler would not “catch”. Therefore, the source code produced by this compiler that runs on the server successfully competes with the code in C. If you compare the cost of providing performance with the effort of programming in other languages, you can see that Ur / Web makes life much easier for a programmer.
The next slide presents a fast benchmark for the performance of this framework for a third-party web infrastructure.
This is a screenshot of the results of the last test, in which various web programming tasks were performed by different frameworks.
You can see that Ur / Web took the 4th place out of the 60 frameworks that participated in the performance tests. After this screenshot was taken, some more improvements were made to the compiler. Therefore, I expect that in the next round, according to its results, it will move up slightly. In principle, this is a simple example of using SQL to generate HTML pages. You get about 100,000 requests per second from an Ur / Web server, and that’s more than enough for most applications. It is important that this slide suggests that you can use a high-level model that provides more security, slightly losing in performance to more common frameworks.
So let me start with pictures that reflect my impression that programmers today think of writing web applications using the most common frameworks. Then I will show the other point of view that Ur / Web provides and according to which, a lot of things that can go wrong go on this framework without errors.
The main picture is the web server on which the entire process of your application depends. And there is a whole park of browsers that are going to interact with this server. The server will be in a certain state, which provides interaction with all these browsers.
The usual pattern is that the browser starts interacting with the web server by sending it an HTTP request that includes the URLs embedded in it. The web server then sends the HTTP and HTML page back to the browser. However, there are some embedded URLs that can be used to determine what kind of request the web server should make in the future.
This web server can also communicate with a database that provides persistent storage common to all users of the application. It uses one popular SQL protocol for conversations between the server network and the database. This is what I will talk about when discussing the possibilities of Ur / Web.
Modern web applications are not just one single page. Whenever something should change on the page, you make a new request to the server, after which the entire module page is replaced. There is an AJAX style, in which the browser, when viewed on one page, sometimes sends additional HTTP requests to the web server and receives responses that are processed by the user program. This usually uses data representations such as XML and JSON, as well as other simple formats for exchanging data between the client and the server.
Then, when the browser returns this response, some JavaScript code is executed there that implements arbitrary logic to control the user interface, which is shown to the user.
This javascript code can read the responses that the server gives to various AJAX calls. It can then change the page, which is basically displayed by changing the global DOM variable that is set for the page. Any part of the program can arbitrarily influence this global variable, which is the page. Often parts of the page are viewed with a string ID annotated with the nodes of the tree describing the document.
And finally, another complication is that sometimes we want the web server to contact the browser without a request. Suppose a new e-mail message appears, and the web server wants to inform the browser about this new message.
And there are many ways to do this, for example, Comet is a model of a web application where a permanent HTTP connection allows a web server to send data to the browser without an additional request from the browser, or the WebSockets duplex communication protocol that communicates between the browser and the server in real time. In principle, these are the same things, but in a conceptually different direction.
So, I want to return all these protocols and languages ​​to the screen, pre-highlighting some parts in yellow. After reading the lecture notes, did anyone guess what is common between all these parts in terms of security?
Student: they all represent lines in which you can put anything.
Professor: correctly, in the generally accepted approach to programming web applications, all these things are string. And the programming language does not understand how you use them, so it cannot help you avoid mistakes. For example, by representing these things as strings, you get code injection attacks. As far as I can tell, attacks with the introduction of code are mainly the result of the inclusion of some function as a primitive in your programming language or your framework, which launches programs as text in a fairly expressive language.
Ur / Web does not have a built-in interpreter for executing strings as programs. And it makes constructively impossible the most common mistakes of web applications. So all these selected objects will be either invisible or represented by special types, which makes it clear which code you are dealing with. In doing so, you do not have any automatic casting of strings to any of these special types.
Now the slide shows an alternative model that is provided by Ur / Web and which is compiled into a traditional model. This is how it works in all common browsers. But the programmer can think about it at a higher level and avoid potential mistakes that were possible in the previous picture.
Thus, we still have a web server that responds to requests. And we still have this park of browsers that are trying to use a web server. But the first important difference is that when the browser wants to start using the web application, it does not just send a string of HTTP requests with a URL.
It runs the first-class function on the server without invoking the client. And then the server responds not just with the text string of the HTTP protocol, but with a strongly typed tree of documents. Thus, instead of the HTML string, we have a tree; in the programming language, an object of the first class. And the program manipulates this tree, not the string.
Each of these trees contains links, which in themselves are just footnotes for other functions that can be called on the server. When a user clicks on these links, the browser selects the function and conceptually calls it on the server, as the original function we called to get to this point.
We also have a database interface that is accessed by a web server that sends requests to the database. In the Ur / Web model, this is not just text, but strongly typed SQL syntax trees. And then the database will respond not with text, but with a list of eigenvalue entries in the Ur programming language with which we work.
Therefore, we don’t need to worry about improperly converting strings to native views or converting native ones to any other format that the database traditionally provides us.
This is a key element in how the Ur / Web semantics make it easier for programmers to work with a large number of scripts that can actually occur while an application is running. There is a standard transaction idea in the world of relational databases, where you can perform a series of operations without interrupting them with other parallel threads. And Ur / Web adapts this model and embeds it into the semantics of the language. Therefore, when one function is executed on the server on behalf of the client, all its access to the database occurs as an atomic unit without any interruption caused by all other simultaneous requests to the same server. You cannot avoid this behavior, even if you want, because these transactions are built into the programming language.
And they do make it easier to perform parallel queries and potentially help avoid security issues that arise when some kind of alternation of queries occurs alternating.
I want to get an answer to one of the questions presented in the abstract of this lecture and which intrigued me. So, Ur / Web detects when a transaction completes with an error due to a parallel execution problem such as a dead end, and automatically restarts the transaction. Someone, answering questions, wrote that it might make it easier to launch security attacks that depend on a transaction failure due to concurrency problems. I just wanted to ask the class if anyone could give an example of such an attack, how do you imagine it? If you have a system that automatically restarts transactions in deadlock situations, how can this cause security problems? I have no answer to this question, which is why I ask. This question may have such an unobvious answer that it is clearly worth discussing.
Student: maybe something like this could cause some kind of a DoS service failure? If he is going to restart the transaction that you are sending, and you know that it will not succeed, you can just continue to restart this process and try again ...
Professor: OK, go on ...
Student: if you force the system to do what, as you know, it will never succeed, you can repeat attempts again and again, and, eventually, cause a service failure.
Professor: correct, but in order to do this, you need at least two threads working simultaneously. Although this could potentially work and you will be able to launch a “service failure” attack. In this case, you can use the fact that request handlers are restarted again and again and deliberately cause a conflict, and use this as a way to increase the power of the DoS attack besides what you can get with the help of the traditional attack model of this type. Well, I can believe it.
Student: Is this the only way to cause a transaction to fail?
Professor: Yes, this is the only way to cause a crash and automatic restart.
Student: there may be a third party that conditionally fails. Then you could use this to monitor the behavior of other users.
Professor: You will also need a way to watch someone fail, but you will be able to do it only after a while. However, this can also be a problem. , , , . , . , , , . .