• Tidak ada hasil yang ditemukan

Write Less, Write Secure

Dalam dokumen DevSecOps for .NET Core PDF (Halaman 73-76)

Software engineers enjoy writing code for applications and sometimes they like to write a lot of code. It is mentioned sometimes that “good software” is well understood by humans. While that statement is true, it does not mean that code has to be written in a verbose manner. By the end of this chapter, we will explore the concept of microservices and how .NET Core can be used to develop (cloud-native4) microservices. Modern runtimes have a steep learning path when it comes to best practices. For ASP.NET Core, many software engineers barely touch the internals of the framework as they develop the software. This means that some effort needs to be made in order to fully explore and understand the platform/framework.

When we talk about the complete deployment suite offered by .NET Core, this becomes a hectic job to make sure that our products are bug free, or that they do not contain any performance or security related issues.

Take an example of a web application5 that finds the orders made by a specific user. A naïve approach to this would be to query the database, fetch all the records, and then process them on the server side. The upside is that all the orders are available in the cache and subsequent queries can be performed quickly, as the data has been loaded into the memory. This code has a problem. Our application is repeating the tasks that a database engine can perform several times better. Relational databases use the SQL language to query the data. SQL exposes several clauses that help database developers write queries that can filter or prepare the data to be presented

4 The cloud-native approach of development takes service orchestration into consideration. Most applications are packaged as containers by Docker or containerization runtimes and are managed and orchestrated by orchestration tools like Kubernetes. The literal meaning of the term is that the application makes good use of the cloud platform, including resources and cloud services such as high-availability, elastic scaling, and global replication.

5 This example is applicable to mobile apps, games, and other platforms, but for a web application it has maximum impact, as data loss affects every user.

back to users. We can improve the efficiency of our program by modifying our queries and returning only the orders made by the specific user. In this case, we will pass the user (or customer) ID as a parameter.

A simple and straight-forward approach is to write a SQL query and replace the user ID with any of the string-replacement methods. These methods can be string interpolation, string concatenation, or string format helpers in C#. This improves the overall performance6 of database engine and our web application. Our database does the heavy lifting of query processing and returns the data that is needed by the application. Our application, on the other hand, can print the data to the user without the need of filtering it. This approach has a minor coding problem that turns into a major production bug. The problem is leaving your SQL inputs unsanitized or unescaped and is called SQL Injection. SQL Injection is one of many “injections” used in computer science and belongs to the bad types of injections. We can solve the problem by properly using escaped SQL. We will come back to this point later in this chapter.

There is no perfect way to write SQL queries. For every task there is a special approach that you can take and author the queries in that case. But the best principles are as follows:

• You must design your relational databases according to the normalization rules. In other words, keep it simple.

• You should write SQL as readable and understandable as possible.

• You should group or filter the data on single columns and avoid using multiple columns in a single clause.

6 Our database query performs well in term of searching because database tables contain indexes that speed up the search process. Once the records are found, transferring smaller chunks of data on the network is fast. Application does not need to process the incoming data, as it is already filtered by database engine.

• You should avoid using asterisk or select-all "*"

in SELECT queries and should try to write the column names for the data.

• You should never concatenate the queries and always use parameters for inputs.

• You can use a JOIN clause or INNER queries to return the data, and then your database can decide how to return the data. Always choose readability in SQL queries.

These points are not even a summary of the best practices7 for SQL. Since databases apply to every domain that .NET Core covers, it’s very important to discuss SQL and NoSQL databases and their pitfalls.

You will find databases being used in mobile apps, web apps, progressive web apps, all the way to games, machine learning apps, and microservices.

Ensuring that SQL best practices are applied on your repositories can help reduce the number of bugs that might show up in the apps.

Several .NET Core object-relational mappers use these practices to ensure security and performance efficiency. Entity Framework Core uses this approach to use LINQ8 to convert the C# expressions into native SQL queries that are executed by the database engine. When you write a LINQ query to fetch the number of posts in your blog, Entity Framework Core converts the function call to the best suitable SQL query, taking security, efficiency, and performance into consideration.

This was merely a discussion about web applications, and things get a lot more interesting when we talk about cloud-native solutions. Cloud platform providers support a wide range of solutions that help developers

7 You can read an impressive SQL best practices guide on Essential SQL, by Kris Wenzel, a fellow CodeProject member, at https://www.essentialsql.com. You can find tips/tricks and best practices for database administration.

8 Entity Framework Core uses LINQ to Entities, a specialization of LINQ to SQL. Learn how Entity Framework Core executes a query at https://docs.

microsoft.com/en-us/ef/core/querying/how-query-works.

deploy their solutions on cloud markets. Tools like Kubernetes, Docker Swarm, DC/OS by Mesosphere, and many others use containers to host and run the application on a cloud infrastructure. In microservices, your solutions must span across several containers, each managing a specific job in the cluster. This architecture solves the availability and scalability issues, but raises problems of:

• Communication

• Encryption

• Consistency

• Service discovery

In later chapters we will solve these problems one by one. With each solution, code complexity increases and makes it difficult to manage the software project. This leads to using service mesh components that manage these tasks for our microservice architectures.

Dalam dokumen DevSecOps for .NET Core PDF (Halaman 73-76)

Dokumen terkait