From 80c2b32b92be3d9dff93e40ecba29aa47411b9b8 Mon Sep 17 00:00:00 2001 From: Jakob Borg Date: Wed, 4 Jun 2014 21:20:07 +0200 Subject: [PATCH] Implement CSRF protection for REST interface (fixes #287) --- auto/gui.files.go | 2 +- cmd/syncthing/gui.go | 3 ++ cmd/syncthing/gui_csrf.go | 111 ++++++++++++++++++++++++++++++++++++++ gui/app.js | 5 ++ 4 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 cmd/syncthing/gui_csrf.go diff --git a/auto/gui.files.go b/auto/gui.files.go index 2cd96e540..1c46967f4 100644 --- a/auto/gui.files.go +++ b/auto/gui.files.go @@ -18,7 +18,7 @@ func init() { bs, _ = ioutil.ReadAll(gr) Assets["angular.min.js"] = bs - bs, _ = hex.DecodeString("1f8b080000096e8800ffec3c6b73db3892dffd2b30bacc929ac89493dbddbb8ae36c659ccc9e372f579ccc87f3f8aa28119238a6488504eda83cfaefd70d80149e146d273399aa5555628968f40b8d467703e0784c8e8bd5ba4ce70b46c2e321797cf0e8afe45ff16531213f16e59cc479420ab6a0259916392bd349cd8ab28ac8f32c23bc57454a5ad1f28a26d11e60fb585152cc085ba415a98aba9c52e89850023fe7c5152d739a90c91ad09237271ff62bb6ce28c9d229cda11f5bc48c4ca1694211d5aca881789ac3734a5e9f1cbf7c7bf692ccd28c467b7be31f7eadb23467645216d740fe0961654d479cc934af69f37b95d515fe13bfc90f63e839cf8a499c91074fc82cce2a008af3799dc5a5fc8d407b410d5f2a9077ca82c3bdbdabb824d53a9f8258f99c1c353da26591d4190d83b62d1891f38be121ef5097d924063447240015713c2d5cc4b55964192dc3e0ac797accca0c30cc6af89d1639091f54d362051c3e5830b61a929b3d021fc4bd2ae9d58b9821f283c3f6e99cb277afe011caba7d8ac4e39209ceb988c009360aecc84a4e39c10a006e368746e32c9ddbcf97eb93172859a03dcd61a811c9f98503c9498e826aecc9f65559b0625a64c70b502c1848cba60243cb120ccfc65d519abfc4369b1b181d9ad9ac9774553492f2e7606b6730d4f9bc02cb9b15252593a2c82a9215c5253c618c963a45c63830f0c29fdfa4c91312bc4e2b4673400423085a98823df19125a7523a2220c8f3248121a96805806cbd025b0d18fdcce0971c2961ac9b9182fc4dfcf98ce6c9abc9aa52d0bfabd9bcc0717d8fa6f03a5da630895fa53f8eabe116775e2f27b4ecc4fe1ef0c5f9490e825ec5d9994241b490a68984b7c62cadcb8d5c36de1dff695cc63089b2f7f4530d40aa7240650414043df384eb680bd21f3f20114669681e91ff04ae8888563100fd55af50f827f746cff3fc651e4f329a28444413799182dd81eb5c6f11a37d76f2fdba987a90f2967be13c2d4ae6474864737f1d9fe1f31f851f57e70e3e26dbe72a9b5aff8fa7f9a92da77842b0d1ddf942f782f33a3d734f6c395fd581f978729fc9fc511714b13daf619183a56b1a73c7ff51137927c2d3b8aaae8b32e946aa4049c4abed934e6e3fbc56a72d2ef1fff3e1c3e919acd0250142bd6ca85177bbb8c16275564fa7942634099bb50d3fe98c84dff1a54c7daa0c559aa72c1c1eea4d61f01f396520cd255f0d8221baff380b83459ad0c080b6174afc6c3416b6cbe62dd9d876ec660261ab45cd92e23aef8674ade03ad31b5bb93fc5e09f6ccdfac52a29abcbdca70ef780f8b47e3389a7974959acc028801ed82098c5255d4f8ab84c64a0b5f10c4a9780ed123e03391608dcc64a2a6f3c5e8a0061d804610f4930aed6306597c06385765755e1b67312b3d8144e37d0439709088cc006f657581e8a7025747327913703a4f6db7e7f37f91556c6087456856ae0328c60d6bd8ca70b05799a5803e354000f88fe81688e027840730ccd3fbe3f392e96ab2207578198faaa475103c77b9e261796264ca9d4ef6e1e9568b4f74861949b17d7401d63628842afc3e148836018548608b3dfc6ce4332268f0e0e0e74c834918eaaf928a136f4d7454307083ac324c5a722eecdb0315ac4d5bbeb1ca2c1152dd99aabda018f9f268b39b45a37d613064bae1b0b12c541014705c10bb0ff26668b68197f0e0f46e4bfc90f42971ce224ff71cd68f5a160b094ef3b12030b0a95c792a1cda146b9a8d92ed210a2f5a1ad8179896f207d64d30509a94fb596520efa8ae000d44763e3f2107a7265ba895d9341243dbde781992ab9c96d0ef7cc7408622d56579a3bc5c7e6da81ab3c24f7daac473898f747907d41ba4e672964f8817b6981d021bfcc71b553bdbb46c1460d03058901ccb1ef908417f3192b562ba0ecc4ccd37726e670809ecf4186b76f7b37e0fceff9c145c48a8f40a03c86a10167fe5034c0b84c2a56868f8687ba1cb2fb1119600a088bed80fcf61bd93e3d49323a306511cd0fa19984832d97583438a5e514fc733ca772601e92c1f7c381535aa9124520c7881f6710fb7dfd014ff359f115463bc1a4abfc6283ad8d5890c2d87829cb8918f8c2a42d9a4a0cbc17d3aa4c973124602e4c0ef51963a81bc5571f4858277d123bd42b2a6cdc5f73fc07fdb06a43b89a32900a2060b570da094e2c4162ec0250783834f5ca57a3595640840664dc6e114b590eb7888f8f675aec8cdca29b0738c7e2253b446fe1efc98b0bdde810d0d44df33cc2a82ca39c2c2a1154e15ad45ad7ba22ace0f14f60845f846255d3df537a2812e2643129c32af4fdd0c4d8e175025e08e0e2b7ded8a1d993294af567d06b71795b7dcae4e4364a5b42b457f9b5653beb6f565db67feca533db19eed499df37a2ac5897f99d352619e34a9365a12edffe8f8ef15654fe8789603881ce75ca2fcacf74e73020333aa7dcd0948d060f9b12e28a9615e076f1f735d593a5b0f6feeca7bd639c61b94d90b0a51d5d5c946089390ddf5751b7590043c6a85a63407e1bb2f9569544603dd4f20d1451e28d329acfd902422ef2c823711b1f74082ab141acec3586b7f1d296d7610d325a91ad3d4394c1c017a1b4e30ce43d9d55900e19758b69a27fc869ffee0e22701bf4ad4b70738873610946b7d01830452f7d9512d622e5e29d869d2adaa59f3ecae9ad199aa44ca9b7bb35331e43a87649494cb0c288310af45db7cddaee622441dead9a64bbd9a4c53ea10e2b81d4fcdb850b8be89d780040c581055d2953df4a28af90bb5554c557b4b78aaaba84ff8a25155bd453b193aa3bc27677f5bb5626faa98eb3caad9d51a7828790d05acbb9f8ec400f4af3a0d6d599ce42c9f250b74990b9a214edb6d93826d76996919c827410044f682b2ba84b16bc8de0c6e629121b1d3cf3f471276186de4aa8bd93ad6f318889634af37cb5cad6c0fe3569f79633dc55cbd67b0e1afa28751ba83166ce22f65605bd708941f2236ab7f98d3abe5782486ca5c9908998dad7a1ce581955ab2c656130c23916af9405f0b3b2007e8e18c494e04189b9cf204a6daba2b20acf400e26e7bfcedebd8d2a7e20209d194a188ec8cd82c6092cfb4fc84d705ce4c013dbff008e3980091ec340caedb6f1af5591071badf8bdd7ed2a06b8f733f055e9b8157bfd80b645a4db9c674feab65b341eb549cc81cf971aa73e54c775769d62b1f69a4e5658c36827334cec9cefbaa8aec03dc186f646408b06d6476439308cb563eedbf3da446625363a6e18d20fe99216356bad3274388b6b88fd8aeb08e73882440a95e6ab4166c4772a3cf3aef3f88ce092ff6f2c2f72ebf14e26e5b6056537d32e58bbf60eadedcfdb1ae5a6a7d939e4c708c419801b016983b62e4b98eab2c783887e86999f843730344d278b152401ea7bf9195c97538d1ad819cd666297cac885b454c89677cb58d49e460037498eda70b57d1cfd5aa439784ee298ae08fc123829cae801d8f169c999d662501cb2466d5f20c049ed0448533c504b934fca567eb528ae0337ae38d981cc358a37aabe80fd649dc74be07fd363248d29e61c4a37ccefafe88442224f772adba2681d46e09b996e95ec3e4de0d243bfa4d6999134f3438dd794a9205a7b780a0e69f2a1385abec78b0b8bd8e7d5f6e2ddfb6fbc8d6f1e1aa88d861ec2de436053687b00bae3b53f244c72a4409d66dbe4cee0e5462429723a22e9e16d05ed65fa6d31c2a17b0baaf5dd66c5002c208ba7341c9331301c00b9f6c97ef344db696ca2588b42ebba5c7efe8e51724b0435692b4a9c76e05be124254ff5892b8a48d0f0f0a1ab94acc29ea7176aa14f5751c73193a6f356e2430b54726e675df8999434beec5162166736009367820b895775b508edb5dfe3e8a2aa2859d85477e392ded51f7d0bf392df0868f8f4458f6a8dd6ebdc7bfb760c7e6c6feea9b775fa8b142236d3bfdfc1aa736388c0300f2db3cf7b56b455e1fd06ea9038ceb2ee71683ca46251dbd1331d8b346aab0ca98029c5beca1d57e3e9134cd67b9a8638ad62db86af1449234cb1c833eb02c04eeb9866342e5f3687633ae344f55681c6e7b9ceb52c9def9347179cad9dcb27ef37e69c7822d95999426291aded618549adb2ba0d4c6e6fbcbc1ea8ae666e13ae781a01ffb7cbd4b475d423b3b28f6dc361478118f0786a1baba28fc13470fa79486f72f71e9a6f97dcc91e5a0dcc9bdc297dc05c32bee1dd8cd98d9d41a8e032fab3ce715ae1df2e52e78d7fb9b00f331b61bb0395dcbcc27ce62f7f71d1da0244b844702736a852dc17b40e2fb958e590784d42a1e45a9bbd7d5f51ba821e0fbb79c34b20cb2aba046097f5edc2deddfedb6fe46f774decd1407b667a48f60b647a90065b66bfd3de6f349b82c06073f704f8f7171973844e99c51db855f12572048d672b4790549c366541b571def985dda6cf722570b0277abb0c886d5ecc519d585c51b99b5cdeb8942341cb1dac284288a8e146b8a2279211b3ec6e0632f811850937bfc689ca16c6e154ec4841c06a6ec7962168e25e813318d910c2b5008cdd9bb7a3cf410c78744ae7109d878dd03831ac6bc8d48643d21e1d5ee96ed075f2c6e8e7426f6731a278d1f41196287ff93219b4fb0a7d41ca0dddb77e7f53a94db580dcac321c4a637d56600d618f6f0a7b1779dc88377309c4a3c5de6d50651c1709955df6e1d0530917e878c2e988dc79232f040f46c4b3dd242ca47b29e9e512bf4cc5501aac66898e655b3bc4734f53fcb394c8f0169a6aa9bbaf41c9f352b7bd5520bb39af15eca078cb8b57cd4c745fae5220e425747ebbc6ae0fec604a8ed22d996aefc37b99f26d5befd8d896b53b6d87c65b7bb270bddda6e32e7857f1c905dc5c8dc7bf6fe255e89f435e04fcecab79a9add7508cf14cfbddc6a39da0dc14d4673b8b02ea2d4e08589b9be8a12e90d87fc50d582e4ecb9aa2d2301e9149c3a5725a2be6e7a6c48586ed792dccb824c0c409609e8993689e4af0a1ab34b2ffc8f2f6b2db33d94daa604fc12aa2468ed72ac01a7845bf2d66d1f559db15b4a3e8862f841eddc4d18bb48458af28d79c74fbab3ff52d82672a029b0734e44c7d79c652c9d033c70aad555996e76513ec4836a4b134c71e6d827c6159aa1433254630f693962ab14cc4004bdc231aaa526762062b2ad5b9c8742e123a4d9778f20a2c7944f25a632649e729abf03ef7b409b27148f0f50bd6650d89fea0e185ff11089a5b7de21e05ff9a1573f1259e70d243bca8d7b63c3a68e215a46c5c0a041ec9bec4ac8b26d8dca82f4f91b5c2208f0122d65f99d2702f7b2b9764f355cd46845f2f7288c89b2356fc947ea649d82a50ebb5f520dc0bd80c4dd23ce6ef54e8cb8f39cbf9433e0cad27f0dd1f3a20de4b4802cb33f0598fff4a7e50ff584920871c1f39400f5d54bbb5f4788817d302f2cff436acf5e1e91eccbce9c74c2717f720ffca4d5ebd8954e28b8e1a7bc03ec12e3b5b527c35d1376467fc9a96f2a7439b26e87decec369cf561e93e66d68b974e26ee41fdf22b1859b5106f72b98b8d69cc3b0f837b88c6d975bcaede366f8df9faf6edbcd7a8b2bf8be3e9a2ce2f4f5e7c61665dacaa371cf849c7b8e4cbb0d032bf7f118ea39b47a3bf6fc6733307e7c03bd1ca471c58a622fbc1ce41e396720a56f6872b411c7a189fff32fee5978bb1530758d117f2c9cdbba747e43f3dc6a11880d3400651148df1aab64058e19bec4215f9fee3a12cb58c073bd588bb82f9fd269ceb951e1c747bcee47b79cec4c74dc223e9f48a8641c1335451ceefe24b6543bc34ef09098e957aaa242edfcad73e66659c57d3ac4eac169e7c99555779601a701fc9af0a898d82962e811cc317123d15668599d6d100dfa33420f97c9fdf133e1ae879f8b9c41941ec3d78f674cc7b3e93143ad554e7e9a79a17cb142575e9e8530d9df1e558f337c889224596e6974fb638b81a468466cb1189192b216a9fb23233ad159f450fc0ee2a5a56519d578b74a69c40be4ae9f5cf71e62ee4f34beb7dca73cd673c26d794c094afb3240f98088d41db4e60c11968f667844ad9dad016df5e38b4bacaaaf5963751f26b05b9e8600edf1689e084a2201589b392c6c9fa4eecf17a9f9fbfdd3ca4151108bfa876ac27d2c65afde87d36d6a67ca739f301c5843e4dfe6dcfbb474c5757b741bb39e08731d0f7f3b3fbad745fe0b0a0a91849a58915feeffcf9feff3edeffaf8b9bbf3dde3c187bdf47741fc9774adf0bb96f2272ec5f6f82fc3f000000ffff010000ffffe4d93fc21f570000") + bs, _ = hex.DecodeString("1f8b080000096e8800ffec3cfd73db36b2bffbaf40f5d223d5c894937777ef4d5ce72675d23b5fbe3c71d279f35cbf194a8424d614a910a06d8dabfffded0220852f52b49db4bd99f34c1b1b58ec17168bdd05c0f1981c17ab7599ce179c84c743f2f4e0c99fc93fe3cb62427e28ca3989f384147c414b322d725ea6938a17258bc88b2c236214232565b4bca249b407d83e314a8a19e18b94115654e594c2c08412f8735e5cd132a70999ac012d797bf2719ff1754649964e690ee3f822e6640a5d138aa8664505c4d31cda29797372fceaddd92b324b331aeded8dbffb856569cec9a42cae81fc33c2cb8a8e0493695ed1faef555631fc4ffe4dbe1bc3c879564ce28c3c7a466671c60028cee7551697ea6f04da0b2af88581bc531e1ceeed5dc52561eb7c0a62e57372548f8896455265340c9abe6044ce2f8687624055669318d01c91005424f0347011303a4be7e1ac8286b4c849f868c1f9eab42caed284964372bb47e0c7688c123a8bab8cb3e88695b37fd018dadec54b41e07ff68fcf3efcb8ffb1b8a43910da31f6b8282e535a8f35466e86369bbc2cb28c96617056b71ef332034135ded9b458812205c99a7754c1aaa4572f638e640e0e9bd639e5ef5f43134ec9b6157514975c2a58cc0470220411d891959c0a820c006e37875627a8d36d5fae4f5ea28c81d19a83452292f30b0f92931c0535d853fdabb2e0c5b4c88e1730ff60c70d9b1a0c2d4b581f2e6e4669fe0afb5c6ec08868e6b25ed255514b2ada61499c8145e673060b645694944c8a22632483d98416ce696952e45c00032fa2fd364d9e91e04dca38cd0111cc2068610a662f66969c2ae98884202f9204a6845106807cbd822515707ac3e12f3553724d6d461af2b7f1cd19cd93d79315d3d0bfaff8bcc079fd80a6f0265da6e06b5ea73f8cd9708b3baf96135a7662ff00f8e2fc240741afe2ec4ca3207b48dd45c23b6356d6e547ae3aef8fff342e635844d907fab902205d39a032020a8291792274b405e98f1f9048a3b4348fc87f048f4964af9c80feaad728fc5d38cd1779fe2a8f27194d3422b28bbc4cc1eec0c3afb788d13e3bf97e534c5b908a9e07e13c2d4ade8e90a8eefe3a3ec3f61fe476a3af1d6c26db769d4d63fca7d3fcd49553b610ecf40fbe30bde0bc4acffc0b5bad577d623e9d3c64317f3205456c2f2ad88b61879dc6c2f17f3244de89f03466ecba28936ea41a9442bcdab67472fbf18dbe6c3112f9c7c78fa7671048940408f5b2a15addcde6069bd559359d529ad024acf736fc496724fc466c657aab3655699ef27078687685c17fe49483349762370886e8fee32c0c16b04d0716b4bb51e2cfc66061bb6dde918dedc06e2610962d2a9e14d77937a46f073799deb8cafd3106ffe46ab65dac92f2aaccdbd4e19f9036addf4ee2e96552162b300aa0073608667149d793222e13150f6e5a26a54bc0660b9f811c0b046e62259d37112f458030ac63c5c72418b3352cd925f0c8d0ee18d382c424e6b12d9c69a0873e139018810d1cafb13c94e14ae8e74e21af27481fb7fdfdfde417d81923d0190bf5c06518c1aa7b154f171af2347126c6ab001110fd0dd11c05d04073cc203e7d38392e96ab2207578198faaa475383c07b9e26178e266ca9f4dffd3c6ad168ef99c228372fae813ac6c410855e87c39101c131a80c1166bf899d87644c9e1c1c1c989069a21c55fda385da30de140d1d20e80c73a93615096f869dd12266efaf73880657b4e46ba16a0f3cfed4c9d6a1d3bb715a386cb97e2c481427051c15042fc0fedb982fa2657c131e8cc87f93efa42e05c449fec39a53f6b1e0b095ef7b1203070a95c793a1cba141b9a8f82ed210a2f5a16d80b512df4096cba70b12d236d53a4a39e82b8207d09c8d8dcf4398c995ed26762d0699f4f45e0776aae427b739dcb3d32188b578c50c778acdf6de81bb7c3133573dc2c1ba3f82ecabca21194e7308c3fc5b0b840ef9658ebb9deedd0d0a2e6a9828480c608d7d83245a319ff162b502ca5ecca2cac0e51a0ed0f379c888feede81a5cfc7b7e7011f1e21310288f616ac0993f961d302f13c6cbf0c9f0d094430d3f22034c0161b31d905f7f25dbd69324a3035b16d9fd18ba4938d872894583535a4ec13fc773aa26e631197c3b1c78a5552ad104f2ccf87106b1dfd79ff0349f155f61b6134cbaca2f36d9c68c0529cc4d2b65b51083b630698b86c9896fc5b42ad3650c09980f93477dd61c9a46f1d52712f6c936893dea958540e1af05fe837e588d295c4d39480510b05b78ed0417962431f601683c1cda7a15bbd12c2b204203327eb788a52c8f5bc4e6e399113b23b7e8e601ceb379a901d13bf8f7e4e58569740868eba66e8f302acba8208b4a0455f836b5c6b5ae082f44fc1358e117a1587c6d1fa93c140971b1d8946117fa766863ecf03a81280408f11b6fecd1ecc914a5fa57d06b7179577daae4e42e4a5b42b4c7dab5e53aeb3facba5cffd84b67ae33dca9b376df88b2625de637d698624c284d9585ba7cfbdf3ae65b53f9ef2682e5043af7a976517ea23ba7019931391586a61d34b4b0a920ae68c900b78fbfafa99e2c85bdf7a776da3be619b6db04093bda31c545099698d3887315fd980530649cea3506e4b7269b6f554924d64323df401115de28a3f99c2f20e4224f5a246ee2830e41153688955b8d411d8cedb40615ada8de9e21ca60d016a134f30ce45b06eb201d329a165347ff90d3fed51f44e069ed3b9fe0f614e7d212ac61a135619a5efa2a25ac64ca25060d3b55b44b3f7d94d35b333449b9566ff76b663c8650ed929298608511631418bb6eba8dd3c54881bc5fd5c9767d968c6342135601e9f9b70f1716d13bf100808e030bba4aa6be95505121f7ab88c557b4b78a5855c2ff8a259527e95379926a3ac2e674f59b4626fab98a33e6d7cea853c14348689ded5cfeec400f4a6b416daa339d858ae5a169932033a314edb63e3826d76996919c827410044f68232ba84b15bcade0c6e52992071d22f36ce34ec10c5b2ba1ee49b679c420178e2dcd8bd52a5b03fbd7a4395bcef0542d5bef796898b3d46da0d69c798bd85b15f4c22527a91d5173cc6fd5f15b2588e4519a0a9988ad7d13ea8c97115b65290f8311aeb178a56d8037da067813718829c18312fb9c4196da5605730acf400e16e73fcfdebf8b98b81090ce2c250c47e476212e88b067e436382e72e089ef7f04c71cc0028f6122d571dbf81756e4c1c6287eef75bb8a019efd0cdaaa74c28a5bfd80714464da5ccb99d45d8f685ad4a630076dbed4baf5a13baeb3eb148bb5d774b2c21a46b3986161e7e2d4457705fe0536740f021a34b03f22cb8165ac1d6bdf5dd7363227b13171c3947e4c97b4a8786395a1c7595c43ec575c47b8c61124d2a8d4bf5a6446e2a4a265dd755e9f915c8aff5bdb8b3a7abc9749f96d413bcd740bd6beb343e7f8f3ae46b9e969761ef93102f106e056405aa3adca1296ba1af128a237b0f293f016a6a61ee4b08224407daf6ec07579d568809dd16c264fa9ac5cc848855c79b78c45cd6d047093e4a809579be6e89722cdc17312cf7245e057c04951468fc08e4f4bc1b41183e294d56afb02014eea264086e2815a9a7cd68ef2d9a2b80efcb8e2640732df2cdeeafa02f693751e2f81ff4d8f99b49698772afd30bfbda2130a893cdda96c87a27319411c66fa55b2fb36814f0ffd925a6f4652af0f3d5ed39682ecede12904a4cd87e668c5192f6e2cf29cd7388bf79fbf893e717868a1b63a7a08fb00816da1dd09e88ed77e9730c99302759a6d9d3b83971b91a4c8e988a4877715b497e937c5088fee1da8c677db1503b0802c9ed2704cc6c07000e49a96fdbac53869aca3588742e3ba7c7efe9e5172430435e92a4ade761047e12425df9b0b571691a0e3f1635f2959873d4f2ff4429fa9a28e6b26f5e0adc4870ea8e2dccdbaf06752d2f8b2478959ded9004c2d0b5c4abcaad82274f7fe164717b1a2e4615ddd8d4b7a5f7ff4475897e2e142cd675bf4a8d7685b9d7b6fdf8ec18febcd5bea6d9dfe228588cdf6eff7b0eadc9a2230cc43c7ecf39e156d5df87603f5481c6759f73cd41e52b3a8edecd98e4519b55386d4c0b4621ff3c7d578fb0493f59ea6216fabb8b6d1568aa411a658e4b9f30060a7754c331a97afeacb319d71a2feaac0e0f3dce45a95cef7c9930bc1d6ceed538c1b0b4e5a22d95999426291addd698545adb3ba0d4cee6ebca21ea8ef667e1366228d80ff37dbd4b471d423bbb28f7dc361478118f0b4d43656451f83a9e1ccfb90adc9dd07e8be5b72a7461835b0d6e44e1b03e6928903ef7ace6edd0c420757d19f738fd309ff76913aaffdcb857b99d90adb3da8d4e115e6337ffa938fd61620c22d4238b1014bf15cd0b9bce4635540e233098d926f6f6e1dfb9ad2158c78dccd1b3e0259b2e812807dd6b70b7b77ffafbf92bfdc37b14703ed99e921d92f90e9411aec98fd4e7bbf356c0a0283cdfd13e0df5e64cc113a65966fe056c597c8110c9e9d1c4151f1da9403d5c479e7176e9fb9cab5c0c15de8cd36208f793147f562f145e57e7279ed528e242d7fb0a20921a3865be98a9e2946ecb2bb1dc8e08f2c4cf8f9b56e5436301ea7e2460a12d6703bae0c411df74a9cc1c88590ae0560dcd1a21f7d0e62c0ab532687e83c5c84d68d615343b6363c92f618f0da7483be9b37d6381f7a378b91c58b7a8cb444f5575b268376cfd017a4c2d0dbf6ef3f546ac316909b31cba1d4d6e704d610f6b42de1d64d1e0fe2ed5c02f118b177135459d74542ed947d386ca9844b7422e1f444eea25314820723d272dc242da47b2be9e512bf4cc55019ac61899e6ddbb8c4f34053fc572991e12b34dd52773f8352f7a5eefaaa400df33e2bd841f18e0fafea95e87f5ca541a847e8e2758d5b1fd8c1949aa53b32d5bc876f65aaedd87ac7c1b6aadd192734adb52707d7bb6d3aee83f7159f7cc0f5d378fcf76dbc0adbd7502b0271f7d57ed4d66b2ac678a7fd7ef3d12c50610a7adbcea280fe8a1302d6fa257a680a24cf5ff1005688d3b0a6a9348c47645273a9ddd68ac5bd29f9a0617b5f0b332e0530f102d877e2149aef15f8d0571ad97fe2787b35ecb91aa654b0a7619551a3c0eb14602dbc72dc16b31cfabc190adad1742336c216ddc4d1cbb48458af28d78274f3577fea5b04cf75042e0f68c899fef18ca596a1679e1ddaa8b22ccfcb3ad8516c2863a9af3dba04c5c6b2d429665a8c609d272d7562998c0196784634d4a5cee40ad6546a7291995c24749a2ef1e61558f288e495c14c92ce53cef03df7b40eb2714af0f30bce630d85fea0e645fc2311d4affae43b0af16b56cce52ff144901ee243bda6e7c9411daf2065eb5120f048f615665334c9e646ff788aaa1506790c10b1f9c9949a7b355a7b249baf2a3e22e279914744d11df1e2c7f4862661a34063d4d683585f73a9199aa4792cbea9d0971f7b958b46310d8d27687b3f74405a1f21492ccfc1673dfd33f94effc7490205e4f8c8037ae8a3daada5a7437c981690bfa77761ad0f4f0f60e66d3f663ab97800f9d77ef2fa4ba412bfc754db038e0976d9d992e21794fe4076269e6969ff7468d3067d889ddd85b33e2c3dc4cc7af1d2c9c403a85f7e0523630bf92597fbd898c1bcf732780bd138bb8ed7ec5dfdd598af6fdfde778d3afbbb389e2eaafcf2e4e51766d6c7aafec241dc748c4bb10d4b2d8bf717e138ba7d32faeb663cb7737001bc13ad6a12c02a15d90f764e9ab09453b0b2df5d09f2d2c3f8fce7f1cf3f5f8cbd3ac08abe944f1dde7d7f44feb3c5383403f01ac8208aa2313ed59608197e702fd491ef3f1daa52cb78b0538d782a983f6cc1f93ee92140b7f74cbe55f74cdab84944249d5ed1302844862acbf95d7ce96cc86ffb3d23c1b1564f55c4d5c7039b665ec6399b6655e2f488e4cbaebaaa0bd380fb48fdaa91d86868e912c871fc20d1f7d2ac30d33a1ae0779406249fef8b77c24703330f3f57382388bd07cfbf1f8b91cf15854e355579fab912c5324d495d3afa5cc160fc38d6fc2d72a24991a5f9e5b32d0ea18611a1d9724462ce4b88daa7bccc6c6bc5b6e811d81da3258baa9c2dd2997603f92aa5d73fc599bf902f1eadf729cfd53fe331b9a604967c952579c065680cdaf6024bce40b33f2154cad796b6c4f1c2a1335455adb7bcc9925f23c8450773f8514b042714056124ce4a1a27eb7bb127ea7dedfcede621654422fca2da715a948d35fa31c76c9c43f94e7316138a097d9afcdb9e77cf98a9ae6e83f673202e63a0ef1777f71be9bec065415b318a4a1d2bfcdff98bfdff7dbaff5f17b77f79ba79346efd1ed14324df297d2fe46d0b5160ff7a0be4ff010000ffff010000ffff8226dc91c6570000") gr, _ = gzip.NewReader(bytes.NewBuffer(bs)) bs, _ = ioutil.ReadAll(gr) Assets["app.js"] = bs diff --git a/cmd/syncthing/gui.go b/cmd/syncthing/gui.go index e6d8b21fa..d98e16a98 100644 --- a/cmd/syncthing/gui.go +++ b/cmd/syncthing/gui.go @@ -105,6 +105,7 @@ func startGUI(cfg config.GUIConfiguration, assetDir string, m *model.Model) erro router.Post("/rest/discovery/hint", restPostDiscoveryHint) mr := martini.New() + mr.Use(csrfMiddleware) if len(cfg.User) > 0 && len(cfg.Password) > 0 { mr.Use(basic(cfg.User, cfg.Password)) } @@ -114,6 +115,8 @@ func startGUI(cfg config.GUIConfiguration, assetDir string, m *model.Model) erro mr.Action(router.Handle) mr.Map(m) + loadCsrfTokens() + go http.Serve(listener, mr) return nil diff --git a/cmd/syncthing/gui_csrf.go b/cmd/syncthing/gui_csrf.go new file mode 100644 index 000000000..f7a39f5a1 --- /dev/null +++ b/cmd/syncthing/gui_csrf.go @@ -0,0 +1,111 @@ +package main + +import ( + "bufio" + "crypto/rand" + "encoding/base64" + "fmt" + "net/http" + "os" + "path/filepath" + "strings" + "sync" + "time" + + "github.com/calmh/syncthing/osutil" +) + +var csrfTokens []string +var csrfMut sync.Mutex + +// Check for CSRF token on /rest/ URLs. If a correct one is not given, reject +// the request with 403. For / and /index.html, set a new CSRF cookie if none +// is currently set. +func csrfMiddleware(w http.ResponseWriter, r *http.Request) { + if strings.HasPrefix(r.URL.Path, "/rest/") { + token := r.Header.Get("X-CSRF-Token") + if !validCsrfToken(token) { + http.Error(w, "CSRF Error", 403) + } + } else if r.URL.Path == "/" || r.URL.Path == "/index.html" { + cookie, err := r.Cookie("CSRF-Token") + if err != nil || !validCsrfToken(cookie.Value) { + cookie = &http.Cookie{ + Name: "CSRF-Token", + Value: newCsrfToken(), + } + http.SetCookie(w, cookie) + } + } +} + +func validCsrfToken(token string) bool { + csrfMut.Lock() + defer csrfMut.Unlock() + for _, t := range csrfTokens { + if t == token { + return true + } + } + return false +} + +func newCsrfToken() string { + bs := make([]byte, 30) + _, err := rand.Reader.Read(bs) + if err != nil { + l.Fatalln(err) + } + + token := base64.StdEncoding.EncodeToString(bs) + + csrfMut.Lock() + csrfTokens = append(csrfTokens, token) + if len(csrfTokens) > 10 { + csrfTokens = csrfTokens[len(csrfTokens)-10:] + } + defer csrfMut.Unlock() + + saveCsrfTokens() + + return token +} + +func saveCsrfTokens() { + name := filepath.Join(confDir, "csrftokens.txt") + tmp := fmt.Sprintf("%s.tmp.%d", name, time.Now().UnixNano()) + + f, err := os.OpenFile(tmp, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0644) + if err != nil { + return + } + defer os.Remove(tmp) + + for _, t := range csrfTokens { + _, err := fmt.Fprintln(f, t) + if err != nil { + return + } + } + + err = f.Close() + if err != nil { + return + } + + osutil.Rename(tmp, name) +} + +func loadCsrfTokens() { + name := filepath.Join(confDir, "csrftokens.txt") + f, err := os.Open(name) + if err != nil { + return + } + defer f.Close() + + s := bufio.NewScanner(f) + for s.Scan() { + csrfTokens = append(csrfTokens, s.Text()) + } +} diff --git a/gui/app.js b/gui/app.js index 69d8fdf4c..4de85a6e0 100644 --- a/gui/app.js +++ b/gui/app.js @@ -10,6 +10,11 @@ var syncthing = angular.module('syncthing', []); var urlbase = 'rest'; +syncthing.config(function ($httpProvider) { + $httpProvider.defaults.xsrfHeaderName = 'X-CSRF-Token'; + $httpProvider.defaults.xsrfCookieName = 'CSRF-Token'; +}); + syncthing.controller('SyncthingCtrl', function ($scope, $http) { var prevDate = 0; var getOK = true;