
0. Rückblick
- Secure the Solana Ecosystem (1) — Hello Solana
- Secure the Solana Ecosystem (2) — Calling Between Programs
- Secure the Solana Ecosystem (3) — Program Upgrade
1. Übersicht
Im vorherigen Blogartikel haben wir besprochen, wie ein Programm aktualisiert wird. In diesem Beitrag werden wir uns mit Problemen im Zusammenhang mit der Zugriffskontrolle befassen, einem der häufigsten und grundlegendsten Sicherheitsthemen im Bereich DeFi.
2. Anweisungen
In Solana exportiert jedes Programm einen einzigen entrypoint, der mit entrypoint! definiert ist. Im Gegensatz zu Ethereum können Clients nur eine einzige Funktion aufrufen, die als Einstiegspunkt definiert ist und üblicherweise process_instruction genannt wird. Die Einstiegspunktfunktion erhält drei Parameter. Dies sind die Programmid des Smart Contracts, die Konten, auf denen das Programm operieren wird, und die Anweisungsdaten. Die Anweisungsdaten geben an, welche Anweisung aufgerufen wird. Die folgende Abbildung zeigt ein Beispiel. Durch Entpacken der Anweisungsdaten werden verschiedene Anweisungen (z. B. Lock, Unlock) ausgewählt. Somit sind die Anweisungen, die vom Einstiegspunkt aus erreichbar sind, für jeden öffentlich und können mit angegebenen Anweisungsdaten ausgeführt werden.

3. Kontenvalidierung
Wie erwähnt, erhält das Programm die Konten, die es lesen oder schreiben muss. Dieses Design wirft zwei Fragen auf. Für die zu lesenden Konten, wie kann garantiert werden, dass die in den Konten gespeicherten Daten vertrauenswürdig sind. Für die zu schreibenden Konten, wie kann garantiert werden, dass nur privilegierte Benutzer Anweisungen aufrufen können, um in die Konten zu schreiben. Im Folgenden veranschaulichen wir das Problem der Zugriffskontrolle. Alle Testcodes finden Sie hier.
3.1 Code-Review (PrivilegeOwner)


Wir definieren zunächst zwei Strukturen, Door und Config. Nur das in der Struktur door angegebene Schlüsselkonto (Zeile 17) kann die erstellte door öffnen. Die Tür kann jedoch nicht geöffnet werden, wenn der Systemstatus gesperrt ist, wie in der Struktur Config (Zeile 81) angegeben.

Wie bereits erwähnt, gibt das Config-Konto an, ob die Tür geöffnet werden kann. In diesem Fall sollte nur ein Config-Konto im Programm vorhanden sein. Um dies zu erreichen, verwenden wir PDA, um die Daten von Config zu speichern. Nach der Initialisierung des Config-Kontos setzen wir das Attribut is_initialized auf true, damit es nicht erneut von Angreifern initialisiert werden kann (Zeile 108 - Zeile 110).

Die Anweisung Open() wird zum Öffnen der Türen verwendet. Die Anweisung empfängt mehrere Konten, darunter das zu öffnende Tür-Konto, das config-Konto und das owner-Konto, das die Tür öffnen soll. Um sicherzustellen, dass die Tür zum Programm gehört und die Konfiguration gültig ist, überprüfen wir den Eigentümer des door-Kontos und des config-Kontos (Zeile 204 - Zeile 205). Dies verhindert, dass böswillige Benutzer gefälschte Konten eingeben. Dies beantwortet unsere erste Frage. Um sicherzustellen, dass das zu lesende Konto vertrauenswürdig ist, müssen wir den Eigentümer des Kontos überprüfen! Beachten Sie, dass nur der Eigentümer des door-Kontos die Tür öffnen kann. In diesem Fall prüfen wir, ob das Eigentümer-Konto der tatsächliche owner der door ist und, was noch wichtiger ist, ob die Anweisung vom Eigentümer autorisiert wurde (Zeile 217 - Zeile 219).

In der Funktion validate_owner() prüfen wir zuerst, ob die öffentlichen Schlüssel dieser beiden Konten übereinstimmen, und überprüfen dann die Signatur des Eigentümers. Dies beantwortet die zweite Frage: Um sicherzustellen, dass nur privilegierte Benutzer die open-Anweisung aufrufen können, müssen wir den Eigentümer und den Unterzeichner des Kontos überprüfen. Die close-Anweisung ähnelt open, und die Details finden Sie im Code.
Wir haben das Programm auf dem Testnetz bereitgestellt und es kann unter folgendem Link gefunden werden.
https://explorer.solana.com/address/2Q7FFMWCthBvc6ubLQRx9TRswvaimmd66VaCAfHwsYuC?cluster=testnet
Alle Testtransaktionen sind unten aufgeführt. Der gesamte Ablauf dieser Transaktionen ist Allocate PDA()-> InitializeDoor()-> InitializeConfig()-> Unlock() -> Open() -> Close().
https://explorer.solana.com/tx/2X9CyMrHTNEvbzXTE95gem2j8spnvsQsabFeSpV8hiNpYjiQPPzLRqt5KN86ZYRjnQvydvs7y5eUjJK7no8knDhk?cluster=testnet
https://explorer.solana.com/tx/2XfVWiXeQeHbpqAEYm3AH2RU6hunnqtr155EC4EAM5Bq9VVZNP6QocAav9cPjEQdJFcQrbsSSxiKadr4HPMov8pz?cluster=testnet
https://explorer.solana.com/tx/5Em41sg7yFXeNpnEJnhUQJanfLWKwjMqiBeNAqEEzFrSN9P8zKKafcv5F7RKT2pseB171qeoa8Uz4fKgazzayCnW?cluster=testnet
https://explorer.solana.com/tx/2PMtzpSgjnKDLGmRWBdUSFBPimWnudCPekUYbWzPzokENFYa4N4ab4HCtynfGrzswFPTgGYKHU8PccUMHv3mXHkR?cluster=testnet
https://explorer.solana.com/tx/3kviP9MqkWGMV4yA7k7yPQ5BGfXmcYLcctmY1u2D7n56eT1nx8jMtDumkUNJy8yA3KkmzrmfQLjqpigc8ehGZzBN?cluster=testnet
https://explorer.solana.com/tx/38iEaJBzuGMLbfcszdVB8pkniezH8JrA3XGq7JdADZTQ4hNQC82GSTUA2bmcypdVy3t7htWnUzkZ4F8EakmNvqz8?cluster=testnet
3.2 Angriffstransaktion
Um die Bedeutung der Eigentümerprüfung und der Signaturprüfung zu zeigen, verwenden wir zwei Angriffsszenarien als Beispiele.
Erstes Szenario
Das erste ist, dass der „Tür“-Eigentümer versucht, die Tür zu öffnen, wenn die config gesperrt ist. Um dies zu erreichen, erstellen wir ein gefälschtes config-Konto in einem anderen Programm und weisen dem Attribut is_lock den Wert false zu. Der Code des benutzerdefinierten Programms ist unten dargestellt.
Wir senden die Transaktion, um das gefälschte config-Konto zu erstellen. Die öffentliche Adresse des gefälschten config-Kontos ist: 2MtSrbWp24VjPZQcSUkiWrvNro7qqKemVCsh3Yxc8LTy.
https://explorer.solana.com/tx/2qSyrL5gdQXmgGCFzmzMm1StFQRkDgWpss9A9jV11q2fgDGM5C1XRuXvbX1N5Dt3q2pRqnmyXHVtXGF5dqadAzpJ?cluster=testnet
Sobald das gefälschte config-Konto erstellt ist, übergeben wir es an das Programm (Zeile 423).

Das Ergebnis ist unten dargestellt. Die Protokollmeldung lautet incorrect program id for instruction, was bedeutet, dass der Eigentümer des config-Kontos das Programm sein muss. Somit kann der Angreifer diese Prüfung nicht umgehen.

Zweites Szenario
Das zweite Szenario ist, dass ein böswilliger Benutzer versucht, die Tür zu öffnen, obwohl die Tür nicht gesperrt ist.

In diesem Fall übergeben wir das tatsächliche Eigentümerkonto an das Programm (Zeile 419) und senden die Transaktion. Das Ergebnis ist unten dargestellt.

Es wird die Meldung Signature verification failed ausgegeben, was bedeutet, dass der tatsächliche Eigentümer die Transaktion unterzeichnen muss, um die Tür zu öffnen. Daher schlägt auch unser zweiter Angriff fehl.
4. Zusammenfassung
In Solana implementieren Anweisungen spezifische Logik basierend auf verschiedenen Konten, die von Clients oder anderen Programmen bereitgestellt werden. Daher ist die korrekte Prüfung der Konten sehr wichtig.
In diesem Artikel stellen wir vor, wie Konten richtig überprüft werden, und verwenden zwei Angriffsszenarien, um die Bedeutung dieser Prüfungen zu veranschaulichen. Bleiben Sie dran und weitere Artikel werden folgen.
Lesen Sie weitere Artikel in dieser Reihe:
- Secure the Solana Ecosystem (1) — Hello Solana
- Secure the Solana Ecosystem (2) — Calling Between Programs
- Secure the Solana Ecosystem (3) — Program Upgrade
- Secure the Solana Ecosystem (5) — Multi-Sig
- Secure the Solana Ecosystem (6) — Multi-Sig2
- Secure the Solana Ecosystem (7) — Type Confusion
Über BlockSec
BlockSec ist ein wegweisendes Blockchain-Sicherheitsunternehmen, das 2021 von einer Gruppe weltweit renommierter Sicherheitsexperten gegründet wurde. Das Unternehmen engagiert sich für die Verbesserung der Sicherheit und Benutzerfreundlichkeit der aufkommenden Web3-Welt, um deren massenhafte Einführung zu erleichtern. Zu diesem Zweck bietet BlockSec Dienstleistungen für die Sicherheitsprüfung von Smart Contracts und EVM-Ketten, die Phalcon-Plattform zur Entwicklung von Sicherheitsmaßnahmen und proaktiven Abwehr von Bedrohungen, die MetaSleuth-Plattform zur Geldverfolgung und Untersuchung sowie die MetaSuites-Erweiterung für Web3-Entwickler, um effizient in der Krypto-Welt zu navigieren.
Bis heute hat das Unternehmen über 300 angesehene Kunden wie MetaMask, Uniswap Foundation, Compound, Forta und PancakeSwap betreut und in zwei Finanzierungsrunden von namhaften Investoren wie Matrix Partners, Vitalbridge Capital und Fenbushi Capital zweistellige Millionenbeträge erhalten.
Offizielle Website: https://blocksec.com/
Offizielles Twitter-Konto: https://twitter.com/BlockSecTeam




