{"id":11345,"date":"2023-11-09T20:00:00","date_gmt":"2023-11-09T18:00:00","guid":{"rendered":"https:\/\/u-labs.de\/portal\/?p=11345"},"modified":"2023-11-04T16:21:15","modified_gmt":"2023-11-04T14:21:15","slug":"eigene-tls-zertifikate-in-java-anwendungen-alles-was-du-zum-truststore-wissen-solltest","status":"publish","type":"post","link":"https:\/\/u-labs.de\/portal\/eigene-tls-zertifikate-in-java-anwendungen-alles-was-du-zum-truststore-wissen-solltest\/","title":{"rendered":"Eigene TLS-Zertifikate in Java-Anwendungen: Alles was du zum TrustStore wissen solltest"},"content":{"rendered":"<p>Der TrustStore von Java wird wichtig, wenn man eigene (Root-) Zertifikate dort hinterlegen m\u00f6chte oder muss. Dies ist vor allem f\u00fcr zwei Umgebungen interessant: Testsysteme, auf denen selbst signierte Zertifikate liegen. Und Unternehmensumgebungen, in denen man mit eigenen Zertifizierungsstellen arbeitet und\/oder sogar Proxy-Servern ausgesetzt ist. <\/p>\n<h2 class=\"wp-block-heading\">Wof\u00fcr wird der Java TrustStore ben\u00f6tigt?<\/h2>\n<p>TLS kennen die meisten wahrscheinlich als Transportverschl\u00fcsselung von HTTPS: Die Meisten Webseiten verschl\u00fcsseln damit den Datenaustausch zum Zielserver, damit unterwegs nichts ausspioniert oder manipuliert werden kann. Es gibt noch weitere Protokolle, welche urspr\u00fcnglich unverschl\u00fcsselt waren und sp\u00e4ter mit TLS um Transportverschl\u00fcsselung erg\u00e4nzt wurden: SMTP ~&gt; SMTPS, IMAP ~&gt; IMAPS, FTP ~&gt; FTPS und einige mehr. <\/p>\n<p>In jedem Falle kommen Zertifikate bei TLS zum Einsatz, denen der Client vertrauen muss. Im Regelfall geschieht dies \u00fcber eine Vertrauenskette: Der Client vertraut entweder der Zertifizierungsstelle, die das Zertifikat ausgestellt hat. Gro\u00dfe Zertifizierungsstellen wie beispielsweise Let&#8217;s Encrypt sind in g\u00e4ngigen Betriebssystemen &amp; Programmen bereits hinterlegt. Betreibt ein Unternehmen eine eigene, interne Zertifizierungsstelle, ist das nicht der Fall &#8211; sie muss h\u00e4ndisch hinterlegt werden. Auch einem selbst signiertes (Test-) Zertifikat wird nicht vertraut. <\/p>\n<p>Es gibt hierf\u00fcr einen <strong>Trust Store<\/strong> im Betriebssystem. <a href=\"https:\/\/ubuntu.com\/server\/docs\/security-trust-store\" data-type=\"link\" data-id=\"https:\/\/ubuntu.com\/server\/docs\/security-trust-store\" target=\"_blank\" rel=\"nofollow\">Unter Ubuntu liegen etwa alle (Root-) Zertifikate unter <strong>\/usr\/local\/share\/ca-certificates<\/strong><\/a>, denen vertraut wird. Einige (v.a. plattform\u00fcbergreifende) Anwendungen und Plattformen nutzen diese nicht, sondern besitzen eigene Speicher. Java ist hier ein Beispiel, Wie es dort funktioniert, wird im folgenden gezeigt. <\/p>\n<h3 class=\"wp-block-heading\">Proxy-Server und MITM<\/h3>\n<p>Setzt ein Unternehmen Proxy-Server zur \u00dcberwachung\/Filterung ein, brechen diese TLS-Verschl\u00fcsselungen auf und verschl\u00fcsseln neu. Es ist hier also keine Ende-zu-Ende Verschl\u00fcsselung bis zum Client mehr, sondern nur bis zum Proxyserver im Unternehmensnetz. Oder gegebenenfalls dem Anbieter, wenn jemand meint, externe Clouddienste wie ZScaler zu nutzen. In jedem Falle l\u00e4sst sich die Integrit\u00e4t der urspr\u00fcnglich genutzten Verschl\u00fcsselung nicht mehr sicherstellen, weswegen der Client dem Proxyserver vertrauen muss. Bei einem internen Unternehmensdienst reicht die unternehmenseigene Zertifizierungsstelle. Im Falle eines externen Dienstes muss man zus\u00e4tzlich dessen Root-Zertifikat vertrauen. Ansonsten brechen Clients die Verbindung ab, da nicht vertrauensw\u00fcrdige Zertifikate bzw. Zertifizierungsstellen als Sicherheitsrisiko gesehen werden.<\/p>\n<h2 class=\"wp-block-heading\">Wo liegt der TrustStore von Java?<\/h2>\n<p>Standardm\u00e4\u00dfig in <strong>$JAVA_HOME\/jre\/lib\/security\/cacerts<\/strong>, wobei <strong>$JAVA_HOME<\/strong> der Basis-Ordner der Java-Installation ist. Wenn ihr Java als Archiv herunterladet und es entpackt, ist dies (ohne Unterordner f\u00fcr die Version) das Heimverzeichnis. Im Folgenden Beispiel von <a href=\"https:\/\/adoptium.net\/de\/temurin\/releases\/?version=11\" data-type=\"link\" data-id=\"https:\/\/adoptium.net\/de\/temurin\/releases\/?version=11\" target=\"_blank\" rel=\"nofollow\">Adoptium OpenJDK<\/a> der Inhalt von <strong>jdk-11.0.20.1+1<\/strong> im Archiv:<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><a href=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2023\/10\/grafik.png\"><img loading=\"lazy\" decoding=\"async\" width=\"947\" height=\"443\" src=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2023\/10\/grafik.png\" alt=\"\" class=\"wp-image-11346\" srcset=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2023\/10\/grafik.png 947w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2023\/10\/grafik-300x140.png 300w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2023\/10\/grafik-768x359.png 768w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2023\/10\/grafik-640x299.png 640w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2023\/10\/grafik-363x170.png 363w\" sizes=\"auto, (max-width: 947px) 100vw, 947px\" \/><\/a><\/figure>\n<\/div>\n<p>Bei einer h\u00e4ndischen Installation w\u00fcrde man dessen Inhalt in ein beliebiges Verzeichnis (gerne \/opt f\u00fcr h\u00e4ndisch installierte, optionale Software) entpacken, beispielsweise <strong>\/opt\/openjdk-11<\/strong>. <\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\" data-line=\"\">sudo mkdir \/opt\/openjdk-11\nsudo chown $USER \/opt\/openjdk-11\n\ntar --strip-components=1 -xf OpenJDK11U-jdk_x64_linux_hotspot_11.0.20.1_1.tar.gz -C \/tmp\/openjdk-11<\/code><\/pre>\n<p>Der TrustStore l\u00e4ge dort in <strong>\/opt\/openjdk-11\/lib\/security\/cacerts<\/strong>:<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><a href=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2023\/10\/grafik-1.png\"><img loading=\"lazy\" decoding=\"async\" width=\"837\" height=\"70\" src=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2023\/10\/grafik-1.png\" alt=\"\" class=\"wp-image-11348\" srcset=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2023\/10\/grafik-1.png 837w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2023\/10\/grafik-1-300x25.png 300w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2023\/10\/grafik-1-768x64.png 768w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2023\/10\/grafik-1-640x54.png 640w\" sizes=\"auto, (max-width: 837px) 100vw, 837px\" \/><\/a><\/figure>\n<\/div>\n<p>Anders kann es aussehen, wenn man Java \u00fcber die Paketverwaltung der Distribution installiert. Auf einem Suse Linux Enterprise (SLES) habe ich ihn beispielsweise in <strong>\/usr\/java\/latest\/lib\/security\/cacerts<\/strong> gefunden, bzw. in einem Unterordner f\u00fcr die jeweilige Version mit Build unter <strong>\/usr\/java<\/strong>. Der Pfad kann variieren, je nachdem welche GNU\/Linux-Distribution und welche Java-Distribution ihr nutzt. Sollte v\u00f6llige Unklarheit herrschen, kann man sich <strong>$JAVA_HOME <\/strong>ausgeben lassen. Ist dies nicht gesetzt, kann man sich den Pfad von Java auch \u00fcber die Properties ausgeben lassen:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\" data-line=\"\">java -XshowSettings:properties -version 2&gt;&amp;1 &gt; \/dev\/null | grep &#039;java.home&#039;\n    java.home = \/usr\/lib\/jvm\/java-21-openjdk<\/code><\/pre>\n<h2 class=\"wp-block-heading\">Einsehen, Hinzuf\u00fcgen und \u00e4ndern von Zertifikaten<\/h2>\n<p>Der TrustStore von Java ist keine Textdatei mit einer Zertifikatskette, sondern eine Bin\u00e4rdatei: Seit Java wird PKCS12 verwendet. Sie muss mit <strong>keytool<\/strong> bearbeitet werden, was wiederum in <strong>$JAVA_HOME<\/strong>\/bin liegt. Mit dem Befehl <strong>-list<\/strong> kann man sich einen \u00dcberblick verschaffen, welche Zertifikate darin liegen. Hier sind es 143 St\u00fcck, die Ausgabe mit den Pr\u00fcfsummen wurde gek\u00fcrzt. Bei jeder Operation fordert das Keytool zur Eingabe eines Passwortes auf. Dies lautet standardm\u00e4\u00dfig <strong>changeit<\/strong> und wird &#8211; wie unter GNU\/Linux \u00fcblich &#8211; beim Tippen nicht angezeigt:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\" data-line=\"\">$JAVA_HOME\/bin\/keytool -list -cacerts -file $JAVA_HOME\/lib\/security\/cacerts\nEnter keystore password:\nKeystore type: JKS\nKeystore provider: SUN\nYour keystore contains 143 entries\n...<\/code><\/pre>\n<p>In den meisten F\u00e4llen wird man den TrustStore um ein neues (Root-) Zertifikat erweitern wollen, dies funktioniert mit dem Befehl <strong>-importcert<\/strong>.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\" data-line=\"\">$JAVA_HOME\/bin\/keytool -importcert -alias meine-ca-2023 -keystore $JAVA_HOME\/lib\/security\/cacerts -file meine-ca-2023.crt\nEnter keystore password:\nOwner: ...\nTrust this certificate? [no]:  yes\nCertificate was added to keystore<\/code><\/pre>\n<p>Das Alias <em>meine-ca<\/em>-2023 ist eine frei w\u00e4hlbare Bezeichnung, die jedoch innerhalb des TrustStore einzigartig sein muss. Mit <strong>-file<\/strong> gebt ihr den Pfad zur Zertifikatsdatei an. Nachdem ihr mit <strong>yes<\/strong> best\u00e4tigt habt, dem Zertifikat zu vertrauen, wird es importiert. Falls das Zertifikat bereits existiert, aber unter einem anderen Alias importiert wurde, warnt euch das Werkzeug.<\/p>\n<p>M\u00f6chte man etwa ein ausgelaufenes Zertifikat entfernen, ist dies mit <strong>-delete<\/strong> m\u00f6glich. Identifiziert wird es anhand des beim hinzuf\u00fcgen definierten Aliases:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\" data-line=\"\">$JAVA_HOME\/bin\/keytool -delete -alias meine-ca-2023 -keystore $JAVA_HOME\/lib\/security\/cacerts<\/code><\/pre>\n<h2 class=\"wp-block-heading\">Verwenden des Stores &amp; Fehlersuche<\/h2>\n<p>Standardm\u00e4\u00dfig l\u00e4dt Java den TrustStore aus dem oben Pfad <strong>$JAVA_HOME\/jre\/lib\/security\/cacerts<\/strong>. In vielen F\u00e4llen ist das auch in Ordnung. Doch es gibt Szenarien (z.B. zum testen), in denen man lieber einen anderen laden m\u00f6chte. Hierf\u00fcr gibt es zwei Eigenschaften (Properties), die man an Java jeweils mit -D \u00fcbergeben kann:<\/p>\n<ul class=\"wp-block-list\">\n<li><strong>javax.net.ssl.trustStore<\/strong> legt den Pfad zur TrustStore-Datei (cacerts) fest, die geladen werden soll<\/li>\n<li><strong>javax.net.ssl.trustStorePassword <\/strong>enth\u00e4lt das dazugeh\u00f6rige Password (Standardm\u00e4\u00dfig <strong>changeit<\/strong>)<\/li>\n<\/ul>\n<p>Zum Start einer Java-Anwendung kann der Aufruf wie folgt aussehen:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\" data-line=\"\">java -Djavax.net.ssl.trustStore=\/tmp\/cacert-test -Djavax.net.ssl.trustStorePassword=changeit WebserviceDemo<\/code><\/pre>\n<h2 class=\"wp-block-heading\">Tests mit einfachem HTTP-Aufruf<\/h2>\n<p>Java ist nicht gerade als leichtgewichtiges, effiziente Plattform bekannt. Durchaus auch dank Spezialisten wie Atlassian: Die haben es geschafft, relativ einfache Anwendungen wie z.B. Bitbucket so aufzubl\u00e4hen, dass sie mehrere Minuten (!) zum Starten ben\u00f6tigen. Und das auf leistungsstarken Servern mit 6 Xeon-Kernen. Gogs, GitTea &amp; diverse weitere realisieren das in Sekunden auf einem Raspberry Pi, ohne tausende Dollar propriet\u00e4re Lizenzgeb\u00fchren daf\u00fcr zu verlangen &#8211; tr\u00e4ge Software ist offensichtlich kein Naturgesetz. Jedenfalls ist es mit solchen Monstern extrem z\u00e4h, derartiges zu testen. Statt mich noch mehr \u00fcber Atlassians <em>Qualit\u00e4t<\/em> aufzuregen, habe ich mir daher eine simple Klasse geschrieben, die eine HTTP-Abfrage durchf\u00fchrt:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-java\" data-line=\"\">import java.io.IOException;\nimport java.net.URI;\nimport java.net.http.HttpClient;\nimport java.net.http.HttpRequest;\nimport java.net.http.HttpResponse;\n\npublic class WebserviceDemo {       \n\tpublic static void main (String[] args) throws IOException, InterruptedException {\n        \tHttpClient client = HttpClient.newHttpClient();\n            \tHttpRequest request = HttpRequest.newBuilder()\n                    .uri(URI.create(&quot;https:\/\/api.ipify.org?format=json&quot;))\n                    .build();\n\t       HttpResponse&lt;String&gt; response = client.send(request,\n              HttpResponse.BodyHandlers.ofString());            \n\t       System.out.println(response.body());\n       }\n}<\/code><\/pre>\n<p>M\u00f6chte man eine interne CA testen, sollte man die Adresse auf eine anpassen, die ein entsprechendes Zertifikat verwendet. Um den Code zu kompilieren, wird das JDK ben\u00f6tigt. Das JRE kann kompilierte Anwendungen nur ausf\u00fchren. Falls ihr das Gl\u00fcck habt, an einer Anwendung zu arbeiten, die (richtigerweise) nur das JRE mitbringt: Ermittelt die Version und ladet euch das JDK in der gleichen herunter. F\u00fcr Tests reicht eine manuelle Installation \u00fcber das Archiv (siehe oben) v\u00f6llig aus, die l\u00f6scht man danach sowieso wieder. Ich nehme in diesem Beispiel die gleiche Version in <strong>$JAVA_HOME<\/strong> und kann nun in einer kleinen, kompakten Anwendung sehr effektiv ausprobieren, ob der TrustStore funktioniert.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\" data-line=\"\">$JAVA_HOME\/bin\/javac WebserviceDemo.java\n$JAVA_HOME\/bin\/java -Djavax.net.ssl.trustStore=\/tmp\/cacert-test -Djavax.net.ssl.trustStorePassword=changeit WebserviceDemo<\/code><\/pre>\n<h2 class=\"wp-block-heading\">Fehlersuche mit Debug-Parametern<\/h2>\n<p>Sollte es nicht wie gew\u00fcnscht funktionieren, ist der Parameter <strong>-Djavax.net.debug=ssl:trustmanager<\/strong> sehr n\u00fctzlich: Er zeigt euch s\u00e4mtliche Debug-Logs zum <a href=\"https:\/\/github.com\/AdoptOpenJDK\/openjdk-jdk11\/blob\/master\/src\/java.base\/share\/classes\/sun\/security\/ssl\/TrustStoreManager.java\" data-type=\"link\" data-id=\"https:\/\/github.com\/AdoptOpenJDK\/openjdk-jdk11\/blob\/master\/src\/java.base\/share\/classes\/sun\/security\/ssl\/TrustStoreManager.java\" target=\"_blank\" rel=\"nofollow\">TrustStoreManager<\/a> von Java an. Damit k\u00f6nnt ihr beispielsweise herausfinden, wo standardm\u00e4\u00dfig nach TrustStores gesucht wird:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\" data-line=\"\">$JAVA_HOME\/bin\/java -Djavax.net.debug=ssl:trustmanager WebserviceDemo\njavax.net.ssl|DEBUG|01|main|2023-10-17 21:39:18.162 CEST|SSLCipher.java:464|jdk.tls.keyLimits:  entry = AES\/GCM\/NoPadding KeyUpdate 2^37. AES\/GCM\/NOPADDING:KEYUPDATE = 137438953472\njavax.net.ssl|DEBUG|01|main|2023-10-17 21:39:18.171 CEST|SSLCipher.java:464|jdk.tls.keyLimits:  entry =  ChaCha20-Poly1305 KeyUpdate 2^37. CHACHA20-POLY1305:KEYUPDATE = 137438953472\njavax.net.ssl|DEBUG|01|main|2023-10-17 21:39:18.182 CEST|TrustStoreManager.java:161|Inaccessible trust store: \/opt\/openjdk-11\/lib\/security\/jssecacerts\njavax.net.ssl|DEBUG|01|main|2023-10-17 21:39:18.183 CEST|TrustStoreManager.java:112|trustStore is: \/opt\/openjdk-11\/lib\/security\/cacerts\ntrustStore type is: pkcs12<\/code><\/pre>\n<p>Dabei zeigt sich beispielsweise, dass Java einen Fallback auf den Standard TrustStore macht, wenn der per <strong>javax.net.ssl.trustStore<\/strong> \u00fcbergebene nicht existiert. Ohne Debug-Flag erfahrt ihr davon nichts und wundert euch, wieso nichts funktioniert, wenn z.B. der Pfad einen Fehler enth\u00e4lt. Ich h\u00e4tte in dem Fall einen Fehler erwartet, mindestens aber eine Warnung. Wenn der Parameter ausdr\u00fccklich gesetzt ist und dieser nicht geladen werden kann, liegt ein Bedienfehler vor. Das sieht Java offensichtlich anders und generiert daraus lediglich einen Debug-Eintrag:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\" data-line=\"\">$JAVA_HOME\/bin\/java -Djavax.net.ssl.trustStore=\/tmp\/not-existing -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.debug=ssl:trustmanager WebserviceDemo\njavax.net.ssl|DEBUG|01|main|2023-10-17 21:42:59.702 CEST|SSLCipher.java:464|jdk.tls.keyLimits:  entry = AES\/GCM\/NoPadding KeyUpdate 2^37. AES\/GCM\/NOPADDING:KEYUPDATE = 137438953472\njavax.net.ssl|DEBUG|01|main|2023-10-17 21:42:59.712 CEST|SSLCipher.java:464|jdk.tls.keyLimits:  entry =  ChaCha20-Poly1305 KeyUpdate 2^37. CHACHA20-POLY1305:KEYUPDATE = 137438953472\njavax.net.ssl|DEBUG|01|main|2023-10-17 21:42:59.723 CEST|TrustStoreManager.java:161|Inaccessible trust store: \/tmp\/not-existing\njavax.net.ssl|DEBUG|01|main|2023-10-17 21:42:59.723 CEST|TrustStoreManager.java:112|trustStore is: \/opt\/openjdk-11\/lib\/security\/cacerts<\/code><\/pre>\n<p>Das d\u00fcrfte in vielen F\u00e4llen gen\u00fcgen. Ansonsten gibt es noch <a href=\"https:\/\/colinpaice.blog\/2020\/04\/05\/using-java-djavax-net-debug-to-examine-data-flows-including-tls\/\" target=\"_blank\" rel=\"nofollow\">eine Reihe weiterer Debug-Optionen<\/a>, die mehr Informationen liefern.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Der TrustStore von Java wird wichtig, wenn man eigene (Root-) Zertifikate dort hinterlegen m\u00f6chte oder muss. Dies ist vor allem f\u00fcr zwei Umgebungen interessant: Testsysteme, auf denen selbst signierte Zertifikate liegen. Und Unternehmensumgebungen, in denen man mit eigenen Zertifizierungsstellen arbeitet und\/oder sogar Proxy-Servern ausgesetzt ist. Wof\u00fcr wird der Java TrustStore ben\u00f6tigt? TLS kennen die meisten &#8230;<\/p>\n","protected":false},"author":5,"featured_media":11505,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[78],"tags":[87,1012],"class_list":["post-11345","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-software","tag-java","tag-tls"],"_links":{"self":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts\/11345","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/comments?post=11345"}],"version-history":[{"count":9,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts\/11345\/revisions"}],"predecessor-version":[{"id":11573,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts\/11345\/revisions\/11573"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/media\/11505"}],"wp:attachment":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/media?parent=11345"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/categories?post=11345"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/tags?post=11345"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}